From 893810f82fefd3c9f23f07702a98b5bca77abde5 Mon Sep 17 00:00:00 2001 From: Michael Mayer Date: Mon, 28 Feb 2022 19:12:54 +0100 Subject: [PATCH] Metadata: Read Zulu formatted timestamps from Exiftool JSON #2082 --- internal/meta/json_exiftool.go | 2 +- internal/meta/json_test.go | 22 ++- internal/meta/testdata/sony_mp4_exiftool.json | 130 ++++++++++++++++++ internal/meta/xmp_document.go | 2 +- 4 files changed, 152 insertions(+), 4 deletions(-) create mode 100755 internal/meta/testdata/sony_mp4_exiftool.json diff --git a/internal/meta/json_exiftool.go b/internal/meta/json_exiftool.go index 4508e8b13..efe1df674 100644 --- a/internal/meta/json_exiftool.go +++ b/internal/meta/json_exiftool.go @@ -84,7 +84,7 @@ func (data *Data) Exiftool(jsonData []byte, originalName string) (err error) { if tv, err := time.Parse("2006:01:02 15:04:05", strings.ReplaceAll(s, "-", ":")); err == nil { fieldValue.Set(reflect.ValueOf(tv.Round(time.Second).UTC())) - } else if tv, err := time.Parse("2006:01:02 15:04:05-07:00", s); err == nil { + } else if tv, err := time.Parse("2006:01:02 15:04:05Z07:00", s); err == nil { fieldValue.Set(reflect.ValueOf(tv.Round(time.Second))) } case time.Duration: diff --git a/internal/meta/json_test.go b/internal/meta/json_test.go index 1ee0689f8..8896fda39 100644 --- a/internal/meta/json_test.go +++ b/internal/meta/json_test.go @@ -732,8 +732,8 @@ func TestJSON(t *testing.T) { // t.Logf("all: %+v", data.All) assert.Equal(t, "Jens\r\tMander", data.Artist) - assert.Equal(t, "0001-01-01T00:00:00Z", data.TakenAt.Format("2006-01-02T15:04:05Z")) - assert.Equal(t, "0001-01-01T00:00:00Z", data.TakenAtLocal.Format("2006-01-02T15:04:05Z")) + assert.Equal(t, "2004-09-23T10:57:57Z", data.TakenAt.Format("2006-01-02T15:04:05Z")) + assert.Equal(t, "2004-09-23T10:57:57Z", data.TakenAtLocal.Format("2006-01-02T15:04:05Z")) assert.Equal(t, "This is the title", data.Title) assert.Equal(t, "", data.Keywords.String()) assert.Equal(t, "This is a\n\ndescription!", data.Description) @@ -891,6 +891,24 @@ func TestJSON(t *testing.T) { assert.Equal(t, 1, data.Orientation) }) + t.Run("sony_mp4_exiftool.json", func(t *testing.T) { + data, err := JSON("testdata/sony_mp4_exiftool.json", "") + + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, "2021-07-06T13:51:36Z", data.TakenAt.Format("2006-01-02T15:04:05Z")) + assert.Equal(t, "2021-07-06T13:51:36Z", data.TakenAtLocal.Format("2006-01-02T15:04:05Z")) + assert.Equal(t, time.UTC.String(), data.TimeZone) + assert.Equal(t, 1080, data.Height) + assert.Equal(t, 1920, data.Width) + assert.Equal(t, float32(0), data.Lat) + assert.Equal(t, float32(0), data.Lng) + assert.Equal(t, 0, data.Altitude) + assert.Equal(t, 1, data.Orientation) + }) + t.Run("Iceland-P3.jpg", func(t *testing.T) { data, err := JSON("testdata/Iceland-P3.json", "") diff --git a/internal/meta/testdata/sony_mp4_exiftool.json b/internal/meta/testdata/sony_mp4_exiftool.json new file mode 100755 index 000000000..05a6734d1 --- /dev/null +++ b/internal/meta/testdata/sony_mp4_exiftool.json @@ -0,0 +1,130 @@ +[{ + "SourceFile": "/go/src/github.com/photoprism/photoprism/storage/import/upload/1646070187605/20210706_155136.MP4", + "ExifToolVersion": 12.16, + "FileName": "20210706_155136.MP4", + "Directory": "/go/src/github.com/photoprism/photoprism/storage/import/upload/1646070187605", + "FileSize": 239103540, + "FileModifyDate": "2022:02:28 17:43:10+00:00", + "FileAccessDate": "2022:02:28 17:43:14+00:00", + "FileInodeChangeDate": "2022:02:28 17:43:10+00:00", + "FilePermissions": 644, + "FileType": "MP4", + "FileTypeExtension": "MP4", + "MIMEType": "video/mp4", + "MajorBrand": "XAVC", + "MinorVersion": "100.1f.ff", + "CompatibleBrands": ["XAVC","mp42","iso2"], + "FileFunctionFlags": 536870912, + "AudioTrackID": 2, + "AudioCodec": "twos", + "AudioAttributes": 0, + "AudioAvgBitrate": 1536000, + "AudioMaxBitrate": 1536000, + "VideoTrackID": 1, + "VideoCodec": "avc1", + "VideoAttributes": 196610, + "VideoAvgBitrate": 50000000, + "VideoMaxBitrate": 50000000, + "VideoAvgFrameRate": 59.94003, + "VideoMaxFrameRate": 59.94003, + "VideoSize": "1920 1080", + "PixelAspectRatio": "1 1", + "MediaDataSize": 239075136, + "MediaDataOffset": 192, + "MovieHeaderVersion": 0, + "TimeScale": 60000, + "Duration": 36.04, + "PreferredRate": 1, + "PreferredVolume": 1, + "PreviewTime": 0, + "PreviewDuration": 0, + "PosterTime": 0, + "SelectionTime": 0, + "SelectionDuration": 0, + "CurrentTime": 0, + "NextTrackID": 4, + "TrackHeaderVersion": 0, + "TrackCreateDate": "2021:07:06 13:51:36", + "TrackModifyDate": "2021:07:06 13:51:36", + "TrackID": 1, + "TrackDuration": 36.036, + "TrackLayer": 0, + "TrackVolume": 0, + "ImageWidth": 1920, + "ImageHeight": 1080, + "GraphicsMode": 0, + "OpColor": "0 0 0", + "CompressorID": "avc1", + "SourceImageWidth": 1920, + "SourceImageHeight": 1080, + "XResolution": 72, + "YResolution": 72, + "CompressorName": "AVC Coding", + "BitDepth": 24, + "VideoFrameRate": 59.9400599400599, + "Balance": 0, + "AudioFormat": "twos", + "AudioChannels": 2, + "AudioBitsPerSample": 16, + "AudioSampleRate": 48000, + "MatrixStructure": "1 0 0 0 1 0 0 0 1", + "ContentDescribes": 1, + "MediaHeaderVersion": 0, + "MediaCreateDate": "2021:07:06 13:51:36", + "MediaModifyDate": "2021:07:06 13:51:36", + "MediaTimeScale": 60000, + "MediaDuration": 36.036, + "MediaLanguageCode": "und", + "MetaFormat": "rtmd", + "TrackProperty": "16 0 0", + "TimeZone": 120, + "HandlerType": "nrtm", + "HandlerDescription": "Non-Real Time Metadata", + "LastUpdate": "2021:07:06 15:51:36+02:00", + "TargetMaterialUmidRef": "060A2B340101010501010D431300000070232CA9019405DC747A90FFFE91DB0B", + "LtcChangeTableTcFps": 30, + "LtcChangeTableHalfStep": true, + "LtcChangeTableLtcChangeFrameCount": 0, + "LtcChangeTableLtcChangeValue": 41185501, + "LtcChangeTableLtcChangeStatus": "increment", + "CreationDateValue": "2021:07:06 15:51:36+02:00", + "VideoFormatVideoRecPortPort": "DIRECT", + "VideoFormatVideoFrameVideoCodec": "AVC_1920_1080_HP@L42", + "VideoFormatVideoFrameCaptureFps": "59.94p", + "VideoFormatVideoFrameFormatFps": "59.94p", + "VideoFormatVideoLayoutPixel": 1920, + "VideoFormatVideoLayoutNumOfVerticalLine": 1080, + "VideoFormatVideoLayoutAspectRatio": "16:9", + "AudioFormatNumOfChannel": 2, + "AudioFormatAudioRecPortPort": "DIRECT", + "AudioFormatAudioRecPortAudioCodec": "LPCM16", + "AudioFormatAudioRecPortTrackDst": "CH1", + "DeviceManufacturer": "Sony", + "DeviceModelName": "ILCE-6400", + "DeviceSerialNo": 4294967295, + "RecordingModeType": "normal", + "RecordingModeCacheRec": false, + "AcquisitionRecordGroupName": "CameraUnitMetadataSet", + "AcquisitionRecordGroupItemName": "CaptureGammaEquation", + "AcquisitionRecordGroupItemValue": "rec709-xvycc", + "XMPToolkit": "Adobe XMP Core 6.0-c006 79.164648, 2021/01/12-15:52:29 ", + "CreateDate": "2021:07:06 13:51:36Z", + "ModifyDate": "2021:07:06 13:51:36Z", + "Rating": 2, + "MetadataDate": "2021:09:27 09:32:57+02:00", + "Orientation": 1, + "InstanceID": "xmp.iid:7bc47715-bddc-4743-a341-8b6b93415b87", + "DocumentID": "xmp.did:7bc47715-bddc-4743-a341-8b6b93415b87", + "OriginalDocumentID": "xmp.did:7bc47715-bddc-4743-a341-8b6b93415b87", + "DurationValue": 2162400, + "DurationScale": 1.66666666666667e-05, + "HistoryAction": "saved", + "HistoryInstanceID": "xmp.iid:7bc47715-bddc-4743-a341-8b6b93415b87", + "HistoryWhen": "2021:09:27 09:32:57+02:00", + "HistorySoftwareAgent": "Adobe Bridge 2021 (Windows)", + "HistoryChanged": "/metadata", + "ImageSize": "1920 1080", + "Megapixels": 2.0736, + "AvgBitrate": 53068843, + "Rotation": 0 +}] diff --git a/internal/meta/xmp_document.go b/internal/meta/xmp_document.go index 0aa6fdb8a..93ab95a82 100644 --- a/internal/meta/xmp_document.go +++ b/internal/meta/xmp_document.go @@ -272,7 +272,7 @@ func (doc *XmpDocument) TakenAt() time.Time { taken = t } else if t, err := time.Parse("2006-01-02T15:04:05.999999999", s); err == nil { taken = t - } else if t, err := time.Parse("2006-01-02T15:04:05-07:00", s); err == nil { + } else if t, err := time.Parse("2006-01-02T15:04:05Z07:00", s); err == nil { taken = t } else if t, err := time.Parse("2006-01-02T15:04:05", s[:19]); err == nil { taken = t