diff --git a/files/file.go b/files/file.go index 1daf384b..3e3214dd 100644 --- a/files/file.go +++ b/files/file.go @@ -19,6 +19,8 @@ import ( "github.com/spf13/afero" + "github.com/rwcarlsen/goexif/exif" + "github.com/filebrowser/filebrowser/v2/errors" "github.com/filebrowser/filebrowser/v2/rules" ) @@ -26,20 +28,22 @@ import ( // FileInfo describes a file. type FileInfo struct { *Listing - Fs afero.Fs `json:"-"` - Path string `json:"path"` - Name string `json:"name"` - Size int64 `json:"size"` - Extension string `json:"extension"` - ModTime time.Time `json:"modified"` - Mode os.FileMode `json:"mode"` - IsDir bool `json:"isDir"` - IsSymlink bool `json:"isSymlink"` - Type string `json:"type"` - Subtitles []string `json:"subtitles,omitempty"` - Content string `json:"content,omitempty"` - Checksums map[string]string `json:"checksums,omitempty"` - Token string `json:"token,omitempty"` + Fs afero.Fs `json:"-"` + Path string `json:"path"` + Name string `json:"name"` + Size int64 `json:"size"` + Extension string `json:"extension"` + ModTime time.Time `json:"modified"` + Mode os.FileMode `json:"mode"` + IsDir bool `json:"isDir"` + IsSymlink bool `json:"isSymlink"` + Type string `json:"type"` + ExifCam string `json:"exifcam,omitempty"` + ExifDate string `json:"exifdate,omitempty"` + Subtitles []string `json:"subtitles,omitempty"` + Content string `json:"content,omitempty"` + Checksums map[string]string `json:"checksums,omitempty"` + Token string `json:"token,omitempty"` } // FileOptions are the options when getting a file info. @@ -232,6 +236,7 @@ func (i *FileInfo) detectType(modify, saveContent, readHeader bool) error { return nil case strings.HasPrefix(mimetype, "image"): i.Type = "image" + i.decodeExif() return nil case strings.HasSuffix(mimetype, "pdf"): i.Type = "pdf" @@ -302,6 +307,50 @@ func (i *FileInfo) detectSubtitles() { } } +func (i *FileInfo) decodeExif() error { + if i.Type != "image" { + return nil + } + + f, err := i.Fs.Open(i.Path) + if err != nil { + return err + } + + x, err := exif.Decode(f) + if err != nil { + return err + } + + camModel, err := x.Get(exif.Model) + if err != nil { + return err + } + + MycamModel, err := camModel.StringVal() + if err != nil { + return err + } + + camMake, err := x.Get(exif.Make) + if err != nil { + return err + } + + MycamMake, err := camMake.StringVal() + if err != nil { + return err + } + + i.ExifCam = MycamMake + " " + MycamModel + + // Two convenience functions exist for date/time taken and GPS coords: + tm, _ := x.DateTime() + i.ExifDate = tm.String() + + return nil +} + func (i *FileInfo) readListing(checker rules.Checker, readHeader bool) error { afs := &afero.Afero{Fs: i.Fs} dir, err := afs.ReadDir(i.Path) diff --git a/frontend/src/components/prompts/Info.vue b/frontend/src/components/prompts/Info.vue index 5312ac76..422baade 100644 --- a/frontend/src/components/prompts/Info.vue +++ b/frontend/src/components/prompts/Info.vue @@ -19,6 +19,24 @@
{{ $t("prompts.lastModified") }}: {{ humanTime }}
++ {{ $t("prompts.exifcam") }}: {{ exifcam }} +
++ {{ $t("prompts.exifdate") }}: {{ exifdate }} +
@@ -113,6 +131,16 @@ export default { modTime: function () { return new Date(Date.parse(this.req.modified)).toLocaleString(); }, + exifcam: function () { + return this.selectedCount === 0 + ? this.req.exifcam + : this.req.items[this.selected[0]].exifcam; + }, + exifdate: function () { + return this.selectedCount === 0 + ? this.req.exifdate + : this.req.items[this.selected[0]].exifdate; + }, name: function () { return this.selectedCount === 0 ? this.req.name diff --git a/frontend/src/i18n/de.json b/frontend/src/i18n/de.json index ad8aadc4..58a19549 100644 --- a/frontend/src/i18n/de.json +++ b/frontend/src/i18n/de.json @@ -132,6 +132,8 @@ "download": "Lade Dateien", "downloadMessage": "Wählen Sie ein Format zum Herunterladen aus.", "error": "Etwas ist schief gelaufen", + "exifcam": "Kamera (Exif)", + "exifdate": "Datum (Exif)", "fileInfo": "Dateiinformation", "filesSelected": "{count} Dateien ausgewählt.", "lastModified": "Zuletzt geändert", diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index a8071114..5fec38a6 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -133,6 +133,8 @@ "download": "Download files", "downloadMessage": "Choose the format you want to download.", "error": "Something went wrong", + "exifcam": "Camera (Exif)", + "exifdate": "Date taken (Exif)", "fileInfo": "File information", "filesSelected": "{count} files selected.", "lastModified": "Last Modified", diff --git a/frontend/src/i18n/fr.json b/frontend/src/i18n/fr.json index 0be93f1a..17a8fa5f 100644 --- a/frontend/src/i18n/fr.json +++ b/frontend/src/i18n/fr.json @@ -132,6 +132,8 @@ "download": "Télécharger", "downloadMessage": "Choisissez le format de téléchargement :", "error": "Quelque chose s'est mal passé", + "exifcam": "Caméra (Exif)", + "exifdate": "Date (Exif)", "fileInfo": "Informations", "filesSelected": "{count} éléments sélectionnés", "lastModified": "Dernière modification", diff --git a/go.mod b/go.mod index b50ba09c..e4aaf937 100644 --- a/go.mod +++ b/go.mod @@ -51,6 +51,7 @@ require ( github.com/pierrec/lz4/v4 v4.1.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/subosito/gotenv v1.4.2 // indirect diff --git a/go.sum b/go.sum index 3b5fde8a..7632d16d 100644 --- a/go.sum +++ b/go.sum @@ -217,6 +217,8 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc= +github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/shirou/gopsutil/v3 v3.23.1 h1:a9KKO+kGLKEvcPIs4W62v0nu3sciVDOOOPUD0Hz7z/4= github.com/shirou/gopsutil/v3 v3.23.1/go.mod h1:NN6mnm5/0k8jw4cBfCnJtr5L7ErOTg18tMNpgFkn0hA= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=