2020-04-07 10:42:42 +02:00
|
|
|
package fs
|
|
|
|
|
|
|
|
import (
|
|
|
|
_ "image/gif" // Import for image.
|
|
|
|
_ "image/jpeg"
|
|
|
|
_ "image/png"
|
2020-04-22 16:39:45 +02:00
|
|
|
"os"
|
2020-04-07 10:42:42 +02:00
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type FileType string
|
|
|
|
|
|
|
|
const (
|
|
|
|
TypeJpeg FileType = "jpg" // JPEG image file.
|
|
|
|
TypePng FileType = "png" // PNG image file.
|
|
|
|
TypeGif FileType = "gif" // GIF image file.
|
|
|
|
TypeTiff FileType = "tiff" // TIFF image file.
|
|
|
|
TypeBitmap FileType = "bmp" // BMP image file.
|
|
|
|
TypeRaw FileType = "raw" // RAW image file.
|
|
|
|
TypeHEIF FileType = "heif" // High Efficiency Image File Format
|
|
|
|
TypeMov FileType = "mov" // Video files.
|
|
|
|
TypeMP4 FileType = "mp4"
|
|
|
|
TypeAvi FileType = "avi"
|
2020-04-22 16:39:45 +02:00
|
|
|
TypeXMP FileType = "xmp" // Adobe XMP sidecar file (XML).
|
|
|
|
TypeAAE FileType = "aae" // Apple sidecar file (XML).
|
|
|
|
TypeXML FileType = "xml" // XML metadata / config / sidecar file.
|
|
|
|
TypeYaml FileType = "yml" // YAML metadata / config / sidecar file.
|
|
|
|
TypeToml FileType = "toml" // Tom's Obvious, Minimal Language sidecar file.
|
|
|
|
TypeJson FileType = "json" // JSON metadata / config / sidecar file.
|
|
|
|
TypeText FileType = "txt" // Text config / sidecar file.
|
|
|
|
TypeMarkdown FileType = "md" // Markdown text sidecar file.
|
|
|
|
TypeOther FileType = "" // Unknown file format.
|
2020-04-07 10:42:42 +02:00
|
|
|
)
|
|
|
|
|
2020-04-22 16:39:45 +02:00
|
|
|
type FileExtensions map[string]FileType
|
|
|
|
type TypeExtensions map[FileType][]string
|
|
|
|
|
2020-05-19 11:00:17 +02:00
|
|
|
const (
|
|
|
|
YamlExt = ".yml"
|
|
|
|
JpegExt = ".jpg"
|
|
|
|
)
|
|
|
|
|
2020-04-07 10:42:42 +02:00
|
|
|
// FileExt contains the filename extensions of file formats known to PhotoPrism.
|
2020-04-22 16:39:45 +02:00
|
|
|
var FileExt = FileExtensions{
|
2020-04-07 10:42:42 +02:00
|
|
|
".bmp": TypeBitmap,
|
|
|
|
".gif": TypeGif,
|
|
|
|
".tif": TypeTiff,
|
|
|
|
".tiff": TypeTiff,
|
|
|
|
".png": TypePng,
|
|
|
|
".crw": TypeRaw,
|
|
|
|
".cr2": TypeRaw,
|
|
|
|
".nef": TypeRaw,
|
|
|
|
".arw": TypeRaw,
|
|
|
|
".dng": TypeRaw,
|
|
|
|
".mov": TypeMov,
|
|
|
|
".avi": TypeAvi,
|
|
|
|
".mp4": TypeMP4,
|
|
|
|
".yml": TypeYaml,
|
2020-04-22 16:39:45 +02:00
|
|
|
".yaml": TypeYaml,
|
2020-04-07 10:42:42 +02:00
|
|
|
".jpg": TypeJpeg,
|
|
|
|
".jpeg": TypeJpeg,
|
2020-04-22 16:39:45 +02:00
|
|
|
".jpe": TypeJpeg,
|
|
|
|
".jif": TypeJpeg,
|
|
|
|
".jfif": TypeJpeg,
|
|
|
|
".jfi": TypeJpeg,
|
|
|
|
".thm": TypeJpeg,
|
2020-04-07 10:42:42 +02:00
|
|
|
".xmp": TypeXMP,
|
|
|
|
".aae": TypeAAE,
|
|
|
|
".heif": TypeHEIF,
|
|
|
|
".heic": TypeHEIF,
|
|
|
|
".3fr": TypeRaw,
|
|
|
|
".ari": TypeRaw,
|
|
|
|
".bay": TypeRaw,
|
|
|
|
".cr3": TypeRaw,
|
|
|
|
".cap": TypeRaw,
|
|
|
|
".data": TypeRaw,
|
|
|
|
".dcs": TypeRaw,
|
|
|
|
".dcr": TypeRaw,
|
|
|
|
".drf": TypeRaw,
|
|
|
|
".eip": TypeRaw,
|
|
|
|
".erf": TypeRaw,
|
|
|
|
".fff": TypeRaw,
|
|
|
|
".gpr": TypeRaw,
|
|
|
|
".iiq": TypeRaw,
|
|
|
|
".k25": TypeRaw,
|
|
|
|
".kdc": TypeRaw,
|
|
|
|
".mdc": TypeRaw,
|
|
|
|
".mef": TypeRaw,
|
|
|
|
".mos": TypeRaw,
|
|
|
|
".mrw": TypeRaw,
|
|
|
|
".nrw": TypeRaw,
|
|
|
|
".obm": TypeRaw,
|
|
|
|
".orf": TypeRaw,
|
|
|
|
".pef": TypeRaw,
|
|
|
|
".ptx": TypeRaw,
|
|
|
|
".pxn": TypeRaw,
|
|
|
|
".r3d": TypeRaw,
|
|
|
|
".raf": TypeRaw,
|
|
|
|
".raw": TypeRaw,
|
|
|
|
".rwl": TypeRaw,
|
|
|
|
".rw2": TypeRaw,
|
|
|
|
".rwz": TypeRaw,
|
|
|
|
".sr2": TypeRaw,
|
|
|
|
".srf": TypeRaw,
|
|
|
|
".srw": TypeRaw,
|
|
|
|
".x3f": TypeRaw,
|
|
|
|
".xml": TypeXML,
|
|
|
|
".txt": TypeText,
|
|
|
|
".md": TypeMarkdown,
|
|
|
|
".json": TypeJson,
|
|
|
|
}
|
|
|
|
|
2020-04-22 16:39:45 +02:00
|
|
|
func (m FileExtensions) TypeExt() TypeExtensions {
|
|
|
|
result := make(TypeExtensions)
|
|
|
|
|
|
|
|
for ext, t := range m {
|
|
|
|
extUpper := strings.ToUpper(ext)
|
|
|
|
if _, ok := result[t]; ok {
|
|
|
|
result[t] = append(result[t], ext, extUpper)
|
|
|
|
} else {
|
|
|
|
result[t] = []string{ext, extUpper}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
var TypeExt = FileExt.TypeExt()
|
|
|
|
|
|
|
|
// Find returns the first filename with the same base name and a given type.
|
|
|
|
func (t FileType) Find(fileName string, stripSequence bool) string {
|
|
|
|
base := Base(fileName, stripSequence)
|
|
|
|
dir := filepath.Dir(fileName)
|
|
|
|
|
|
|
|
prefix := filepath.Join(dir, base)
|
|
|
|
prefixLower := filepath.Join(dir, strings.ToLower(base))
|
|
|
|
prefixUpper := filepath.Join(dir, strings.ToUpper(base))
|
|
|
|
|
|
|
|
for _, ext := range TypeExt[t] {
|
|
|
|
if info, err := os.Stat(prefix + ext); err == nil && info.Mode().IsRegular() {
|
|
|
|
return filepath.Join(dir, info.Name())
|
|
|
|
}
|
|
|
|
|
|
|
|
if info, err := os.Stat(prefixLower + ext); err == nil && info.Mode().IsRegular() {
|
|
|
|
return filepath.Join(dir, info.Name())
|
|
|
|
}
|
|
|
|
|
|
|
|
if info, err := os.Stat(prefixUpper + ext); err == nil && info.Mode().IsRegular() {
|
|
|
|
return filepath.Join(dir, info.Name())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2020-05-18 15:45:55 +02:00
|
|
|
// Find returns the first filename with the same base name and a given type (also searches a sub directory).
|
|
|
|
func (t FileType) FindSub(fileName, subDir string, stripSequence bool) string {
|
|
|
|
base := Base(fileName, stripSequence)
|
|
|
|
dir := filepath.Dir(fileName)
|
|
|
|
|
|
|
|
prefix := filepath.Join(dir, base)
|
|
|
|
prefixLower := filepath.Join(dir, strings.ToLower(base))
|
|
|
|
prefixUpper := filepath.Join(dir, strings.ToUpper(base))
|
|
|
|
|
|
|
|
prefixHidden := filepath.Join(dir, subDir, base)
|
|
|
|
prefixLowerHidden := filepath.Join(dir, subDir, strings.ToLower(base))
|
|
|
|
prefixUpperHidden := filepath.Join(dir, subDir, strings.ToUpper(base))
|
|
|
|
|
|
|
|
for _, ext := range TypeExt[t] {
|
|
|
|
if info, err := os.Stat(prefix + ext); err == nil && info.Mode().IsRegular() {
|
|
|
|
return filepath.Join(dir, info.Name())
|
|
|
|
}
|
|
|
|
|
|
|
|
if info, err := os.Stat(prefixLower + ext); err == nil && info.Mode().IsRegular() {
|
|
|
|
return filepath.Join(dir, info.Name())
|
|
|
|
}
|
|
|
|
|
|
|
|
if info, err := os.Stat(prefixUpper + ext); err == nil && info.Mode().IsRegular() {
|
|
|
|
return filepath.Join(dir, info.Name())
|
|
|
|
}
|
|
|
|
|
|
|
|
if info, err := os.Stat(prefixHidden + ext); err == nil && info.Mode().IsRegular() {
|
|
|
|
return filepath.Join(dir, subDir, info.Name())
|
|
|
|
}
|
|
|
|
|
|
|
|
if info, err := os.Stat(prefixLowerHidden + ext); err == nil && info.Mode().IsRegular() {
|
|
|
|
return filepath.Join(dir, subDir, info.Name())
|
|
|
|
}
|
|
|
|
|
|
|
|
if info, err := os.Stat(prefixUpperHidden + ext); err == nil && info.Mode().IsRegular() {
|
|
|
|
return filepath.Join(dir, subDir, info.Name())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2020-04-22 16:39:45 +02:00
|
|
|
// GetFileType returns the (expected) type for a given file name.
|
2020-04-07 10:42:42 +02:00
|
|
|
func GetFileType(fileName string) FileType {
|
|
|
|
fileExt := strings.ToLower(filepath.Ext(fileName))
|
|
|
|
result, ok := FileExt[fileExt]
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
result = TypeOther
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|