Metadata: Add support for CreationDate in ExifTool JSON files #727

This commit is contained in:
Michael Mayer 2020-12-22 07:47:16 +01:00
parent 48fba799a2
commit 2ed6880270
5 changed files with 243 additions and 4 deletions

View file

@ -13,8 +13,8 @@ import (
type Data struct {
DocumentID string `meta:"ImageUniqueID,OriginalDocumentID,DocumentID"`
InstanceID string `meta:"InstanceID,DocumentID"`
TakenAt time.Time `meta:"DateTimeOriginal,CreateDate,MediaCreateDate,ContentCreateDate,DateTimeDigitized,DateTime"`
TakenAtLocal time.Time `meta:"DateTimeOriginal,CreateDate,MediaCreateDate,ContentCreateDate,DateTimeDigitized,DateTime"`
TakenAt time.Time `meta:"DateTimeOriginal,CreationDate,CreateDate,MediaCreateDate,ContentCreateDate,DateTimeDigitized,DateTime"`
TakenAtLocal time.Time `meta:"DateTimeOriginal,CreationDate,CreateDate,MediaCreateDate,ContentCreateDate,DateTimeDigitized,DateTime"`
TimeZone string `meta:"-"`
Duration time.Duration `meta:"Duration,MediaDuration,TrackDuration"`
Codec string `meta:"CompressorID,Compression,FileType"`

View file

@ -131,6 +131,12 @@ func (data *Data) Exiftool(jsonData []byte, originalName string) (err error) {
log.Errorf("metadata: %s (exiftool)", err.Error()) // this should never happen
}
}
} else if _, offset := data.TakenAtLocal.Zone(); offset != 0 && !data.TakenAtLocal.IsZero() {
if localUtc, err := time.ParseInLocation("2006:01:02 15:04:05", data.TakenAtLocal.Format("2006:01:02 15:04:05"), time.UTC); err == nil {
data.TakenAtLocal = localUtc
}
data.TakenAt = data.TakenAt.Round(time.Second).UTC()
}
if orientation, ok := jsonStrings["Orientation"]; ok && orientation != "" {

View file

@ -1,6 +1,7 @@
package meta
import (
"github.com/photoprism/photoprism/pkg/fs"
"testing"
"github.com/stretchr/testify/assert"
@ -18,8 +19,8 @@ func TestJSON(t *testing.T) {
assert.Equal(t, CodecAvc1, data.Codec)
assert.Equal(t, "3s", data.Duration.String())
assert.Equal(t, "2018-09-08 17:20:14 +0000 UTC", data.TakenAtLocal.String())
assert.Equal(t, "2018-09-08 15:20:14 +0000 UTC", data.TakenAt.String())
assert.Equal(t, "2018-09-08 19:20:14 +0000 UTC", data.TakenAtLocal.String())
assert.Equal(t, "2018-09-08 17:20:14 +0000 UTC", data.TakenAt.String())
assert.Equal(t, "Europe/Berlin", data.TimeZone)
assert.Equal(t, 1920, data.Width)
assert.Equal(t, 1080, data.Height)
@ -575,4 +576,52 @@ func TestJSON(t *testing.T) {
assert.Equal(t, "iPhone 6 Plus", data.CameraModel)
assert.Equal(t, "", data.LensModel)
})
t.Run("date-creation.mov.json", func(t *testing.T) {
data, err := JSON("testdata/date-creation.mov.json", "")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, string(fs.CodecAvc), data.Codec)
assert.Equal(t, "10s", data.Duration.String())
assert.Equal(t, "2015-12-06 18:22:29 +0000 UTC", data.TakenAtLocal.String())
assert.Equal(t, "2015-12-06 15:22:29 +0000 UTC", data.TakenAt.String())
assert.Equal(t, "Europe/Moscow", data.TimeZone)
assert.Equal(t, 1920, data.Width)
assert.Equal(t, 1080, data.Height)
assert.Equal(t, 1920, data.ActualWidth())
assert.Equal(t, 1080, data.ActualHeight())
assert.Equal(t, 1, data.Orientation)
assert.Equal(t, float32(55.7579), data.Lat)
assert.Equal(t, float32(37.6197), data.Lng)
assert.Equal(t, "Apple", data.CameraMake)
assert.Equal(t, "iPhone 6 Plus", data.CameraModel)
assert.Equal(t, "", data.LensModel)
})
t.Run("date-iphone8.mov.json", func(t *testing.T) {
data, err := JSON("testdata/date-iphone8.mov.json", "")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, string(fs.CodecHvc), data.Codec)
assert.Equal(t, "6s", data.Duration.String())
assert.Equal(t, "2020-12-22 02:45:43 +0000 UTC", data.TakenAtLocal.String())
assert.Equal(t, "2020-12-22 01:45:43 +0000 UTC", data.TakenAt.String())
assert.Equal(t, "", data.TimeZone)
assert.Equal(t, 1920, data.Width)
assert.Equal(t, 1080, data.Height)
assert.Equal(t, 1080, data.ActualWidth())
assert.Equal(t, 1920, data.ActualHeight())
assert.Equal(t, 6, data.Orientation)
assert.Equal(t, float32(0), data.Lat)
assert.Equal(t, float32(0), data.Lng)
assert.Equal(t, "Apple", data.CameraMake)
assert.Equal(t, "iPhone 8", data.CameraModel)
assert.Equal(t, "", data.LensModel)
})
}

View file

@ -0,0 +1,95 @@
[{
"SourceFile": "IMG_4561.MOV",
"ExifToolVersion": 12.00,
"FileName": "IMG_4561.MOV",
"Directory": ".",
"FileSize": "22 MB",
"FileModifyDate": "2020:07:16 19:06:26+02:00",
"FileAccessDate": "2020:12:22 02:37:08+01:00",
"FileInodeChangeDate": "2020:12:22 02:07:04+01:00",
"FilePermissions": "rw-------",
"FileType": "MOV",
"FileTypeExtension": "mov",
"MIMEType": "video/quicktime",
"MajorBrand": "Apple QuickTime (.MOV/QT)",
"MinorVersion": "0.0.0",
"CompatibleBrands": ["qt "],
"MediaDataSize": 23138648,
"MediaDataOffset": 36,
"MovieHeaderVersion": 0,
"CreateDate": "2015:12:06 15:22:29",
"ModifyDate": "2015:12:06 15:22:40",
"TimeScale": 600,
"Duration": "10.67 s",
"PreferredRate": 1,
"PreferredVolume": "100.00%",
"PreviewTime": "0 s",
"PreviewDuration": "0 s",
"PosterTime": "0 s",
"SelectionTime": "0 s",
"SelectionDuration": "0 s",
"CurrentTime": "0 s",
"NextTrackID": 5,
"TrackHeaderVersion": 0,
"TrackCreateDate": "2015:12:06 15:22:29",
"TrackModifyDate": "2015:12:06 15:22:40",
"TrackID": 1,
"TrackDuration": "10.67 s",
"TrackLayer": 0,
"TrackVolume": "100.00%",
"ImageWidth": 1920,
"ImageHeight": 1080,
"CleanApertureDimensions": "1920x1080",
"ProductionApertureDimensions": "1920x1080",
"EncodedPixelsDimensions": "1920x1080",
"GraphicsMode": "ditherCopy",
"OpColor": "32768 32768 32768",
"CompressorID": "avc1",
"SourceImageWidth": 1920,
"SourceImageHeight": 1080,
"XResolution": 72,
"YResolution": 72,
"CompressorName": "H.264",
"BitDepth": 24,
"VideoFrameRate": 29.981,
"Balance": 0,
"AudioFormat": "mp4a",
"AudioBitsPerSample": 16,
"AudioSampleRate": 44100,
"LayoutFlags": "Mono",
"AudioChannels": 1,
"PurchaseFileFormat": "mp4a",
"Warning": "[minor] The ExtractEmbedded option may find more tags in the media data",
"MatrixStructure": "1 0 0 0 1 0 0 0 1",
"ContentDescribes": "Track 1",
"MediaHeaderVersion": 0,
"MediaCreateDate": "2015:12:06 15:22:29",
"MediaModifyDate": "2015:12:06 15:22:40",
"MediaTimeScale": 600,
"MediaDuration": "10.67 s",
"MediaLanguageCode": "und",
"GenMediaVersion": 0,
"GenFlags": "0 0 0",
"GenGraphicsMode": "ditherCopy",
"GenOpColor": "32768 32768 32768",
"GenBalance": 0,
"HandlerClass": "Data Handler",
"HandlerVendorID": "Apple",
"HandlerDescription": "Core Media Data Handler",
"MetaFormat": "mebx",
"HandlerType": "Metadata Tags",
"GPSCoordinates": "55 deg 45' 28.44\" N, 37 deg 37' 10.92\" E, 135.89 m Above Sea Level",
"Make": "Apple",
"Model": "iPhone 6 Plus",
"Software": 9.1,
"CreationDate": "2015:12:06 18:22:29+03:00",
"ImageSize": "1920x1080",
"Megapixels": 2.1,
"AvgBitrate": "17.3 Mbps",
"GPSAltitude": "135.89 m",
"GPSAltitudeRef": "Above Sea Level",
"GPSLatitude": "55 deg 45' 28.44\" N",
"GPSLongitude": "37 deg 37' 10.92\" E",
"Rotation": 0,
"GPSPosition": "55 deg 45' 28.44\" N, 37 deg 37' 10.92\" E"
}]

View file

@ -0,0 +1,89 @@
[{
"SourceFile": "IMG_6884.MOV",
"ExifToolVersion": 12.00,
"FileName": "IMG_6884.MOV",
"Directory": ".",
"FileSize": "9.6 MB",
"FileModifyDate": "2020:12:22 02:46:08+01:00",
"FileAccessDate": "2020:12:22 02:48:31+01:00",
"FileInodeChangeDate": "2020:12:22 02:46:24+01:00",
"FilePermissions": "rw-r--r--",
"FileType": "MOV",
"FileTypeExtension": "mov",
"MIMEType": "video/quicktime",
"MajorBrand": "Apple QuickTime (.MOV/QT)",
"MinorVersion": "0.0.0",
"CompatibleBrands": ["qt "],
"MediaDataSize": 10091927,
"MediaDataOffset": 36,
"MovieHeaderVersion": 0,
"CreateDate": "2020:12:22 01:46:08",
"ModifyDate": "2020:12:22 01:46:08",
"TimeScale": 600,
"Duration": "6.83 s",
"PreferredRate": 1,
"PreferredVolume": "100.00%",
"PreviewTime": "0 s",
"PreviewDuration": "0 s",
"PosterTime": "0 s",
"SelectionTime": "0 s",
"SelectionDuration": "0 s",
"CurrentTime": "0 s",
"NextTrackID": 5,
"TrackHeaderVersion": 0,
"TrackCreateDate": "2020:12:22 01:46:08",
"TrackModifyDate": "2020:12:22 01:46:08",
"TrackID": 1,
"TrackDuration": "6.83 s",
"TrackLayer": 0,
"TrackVolume": "0.00%",
"ImageWidth": 1920,
"ImageHeight": 1080,
"CleanApertureDimensions": "1920x1080",
"ProductionApertureDimensions": "1920x1080",
"EncodedPixelsDimensions": "1920x1080",
"GraphicsMode": "ditherCopy",
"OpColor": "32768 32768 32768",
"CompressorID": "hvc1",
"SourceImageWidth": 1920,
"SourceImageHeight": 1080,
"XResolution": 72,
"YResolution": 72,
"CompressorName": "HEVC",
"BitDepth": 24,
"VideoFrameRate": 60,
"Balance": 0,
"AudioFormat": "mp4a",
"AudioChannels": 1,
"AudioBitsPerSample": 16,
"AudioSampleRate": 44100,
"PurchaseFileFormat": "mp4a",
"Warning": "[minor] The ExtractEmbedded option may find more tags in the media data",
"MatrixStructure": "1 0 0 0 1 0 0 0 1",
"ContentDescribes": "Track 1",
"MediaHeaderVersion": 0,
"MediaCreateDate": "2020:12:22 01:46:08",
"MediaModifyDate": "2020:12:22 01:46:08",
"MediaTimeScale": 600,
"MediaDuration": "6.83 s",
"MediaLanguageCode": "und",
"GenMediaVersion": 0,
"GenFlags": "0 0 0",
"GenGraphicsMode": "ditherCopy",
"GenOpColor": "32768 32768 32768",
"GenBalance": 0,
"HandlerClass": "Data Handler",
"HandlerVendorID": "Apple",
"HandlerDescription": "Core Media Data Handler",
"MetaFormat": "mebx",
"HandlerType": "Metadata Tags",
"LocationAccuracyHorizontal": 65.000000,
"Make": "Apple",
"Model": "iPhone 8",
"Software": 14.3,
"CreationDate": "2020:12:22 02:45:43+01:00",
"ImageSize": "1920x1080",
"Megapixels": 2.1,
"AvgBitrate": "11.8 Mbps",
"Rotation": 90
}]