Metadata: Add support for XMP sidecar CreateDate and Keywords #1151

This commit is contained in:
Michael Mayer 2021-04-26 13:28:08 +02:00
parent 70c28054b5
commit 8c214a07cd
4 changed files with 37 additions and 20 deletions

View file

@ -57,13 +57,12 @@ func (data *Data) XMP(fileName string) (err error) {
data.LensModel = doc.LensModel() data.LensModel = doc.LensModel()
} }
if takenAt := doc.DateCreated(); !takenAt.IsZero() { if takenAt := doc.TakenAt(); !takenAt.IsZero() {
data.TakenAt = takenAt data.TakenAt = takenAt
} }
if len(doc.Keywords()) != 0 { if len(doc.Keywords()) != 0 {
data.Keywords += doc.Keywords() data.AddKeywords(doc.Keywords())
data.Keywords = SanitizeMeta(data.Keywords)
} }
return nil return nil

View file

@ -198,6 +198,7 @@ type XmpDocument struct {
} `xml:"RDF" json:"rdf,omitempty"` } `xml:"RDF" json:"rdf,omitempty"`
} }
// Load parses an XMP file and populates document values with its contents.
func (doc *XmpDocument) Load(filename string) error { func (doc *XmpDocument) Load(filename string) error {
data, err := ioutil.ReadFile(filename) data, err := ioutil.ReadFile(filename)
@ -208,6 +209,7 @@ func (doc *XmpDocument) Load(filename string) error {
return xml.Unmarshal(data, doc) return xml.Unmarshal(data, doc)
} }
// Title returns the XMP document title.
func (doc *XmpDocument) Title() string { func (doc *XmpDocument) Title() string {
t := doc.RDF.Description.Title.Alt.Li.Text t := doc.RDF.Description.Title.Alt.Li.Text
t2 := doc.RDF.Description.Title.Text t2 := doc.RDF.Description.Title.Text
@ -219,10 +221,12 @@ func (doc *XmpDocument) Title() string {
return "" return ""
} }
// Artist returns the XMP document artist.
func (doc *XmpDocument) Artist() string { func (doc *XmpDocument) Artist() string {
return SanitizeString(doc.RDF.Description.Creator.Seq.Li) return SanitizeString(doc.RDF.Description.Creator.Seq.Li)
} }
// Description returns the XMP document description.
func (doc *XmpDocument) Description() string { func (doc *XmpDocument) Description() string {
d := doc.RDF.Description.Description.Alt.Li.Text d := doc.RDF.Description.Description.Alt.Li.Text
d2 := doc.RDF.Description.Description.Text d2 := doc.RDF.Description.Description.Text
@ -234,34 +238,50 @@ func (doc *XmpDocument) Description() string {
return "" return ""
} }
// Copyright returns the XMP document copyright info.
func (doc *XmpDocument) Copyright() string { func (doc *XmpDocument) Copyright() string {
return SanitizeString(doc.RDF.Description.Rights.Alt.Li.Text) return SanitizeString(doc.RDF.Description.Rights.Alt.Li.Text)
} }
// CameraMake returns the XMP document camera make name.
func (doc *XmpDocument) CameraMake() string { func (doc *XmpDocument) CameraMake() string {
return SanitizeString(doc.RDF.Description.Make) return SanitizeString(doc.RDF.Description.Make)
} }
// CameraModel returns the XMP document camera model name.
func (doc *XmpDocument) CameraModel() string { func (doc *XmpDocument) CameraModel() string {
return SanitizeString(doc.RDF.Description.Model) return SanitizeString(doc.RDF.Description.Model)
} }
// LensModel returns the XMP document lens model name.
func (doc *XmpDocument) LensModel() string { func (doc *XmpDocument) LensModel() string {
return SanitizeString(doc.RDF.Description.LensModel) return SanitizeString(doc.RDF.Description.LensModel)
} }
func (doc *XmpDocument) DateCreated() time.Time { // TakenAt returns the XMP document taken date.
s := doc.RDF.Description.DateCreated func (doc *XmpDocument) TakenAt() time.Time {
taken := time.Time{} // Unknown
if tv, err := time.Parse(time.RFC3339, s); err == nil { s := SanitizeString(doc.RDF.Description.DateCreated)
return tv
} else if tv2, err2 := time.Parse("2006-01-02T15:04:05.999999999", s); err2 == nil { if s == "" {
return tv2 return taken
} }
return time.Time{} if t, err := time.Parse(time.RFC3339, s); err == nil {
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 {
taken = t
} else if t, err := time.Parse("2006-01-02T15:04:05", s[:19]); err == nil {
taken = t
} }
return taken
}
// Keywords returns the XMP document keywords.
func (doc *XmpDocument) Keywords() string { func (doc *XmpDocument) Keywords() string {
s := doc.RDF.Description.Subject.Seq.Li s := doc.RDF.Description.Subject.Seq.Li

View file

@ -18,7 +18,7 @@ func TestXMP(t *testing.T) {
assert.Equal(t, "Botanischer Garten", data.Title) assert.Equal(t, "Botanischer Garten", data.Title)
assert.Equal(t, time.Date(2021, 3, 24, 13, 07, 29, 0, time.FixedZone("", +3600)), data.TakenAt) assert.Equal(t, time.Date(2021, 3, 24, 13, 07, 29, 0, time.FixedZone("", +3600)), data.TakenAt)
assert.Equal(t, "Tulpen am See", data.Description) assert.Equal(t, "Tulpen am See", data.Description)
assert.Equal(t, "Krokus, Blume, Schöne Wiese", data.Keywords) assert.Equal(t, Keywords{"blume", "krokus", "schöne", "wiese"}, data.Keywords)
}) })
t.Run("photoshop", func(t *testing.T) { t.Run("photoshop", func(t *testing.T) {

View file

@ -13,7 +13,7 @@ import (
) )
func TestIndexRelated(t *testing.T) { func TestIndexRelated(t *testing.T) {
t.Run("/2018-04-12 19_24_49.gif", func(t *testing.T) { t.Run("2018-04-12 19_24_49.gif", func(t *testing.T) {
conf := config.TestConfig() conf := config.TestConfig()
testFile, err := NewMediaFile("testdata/2018-04-12 19_24_49.gif") testFile, err := NewMediaFile("testdata/2018-04-12 19_24_49.gif")
@ -35,7 +35,7 @@ func TestIndexRelated(t *testing.T) {
dest := filepath.Join(testPath, f.BaseName()) dest := filepath.Join(testPath, f.BaseName())
if err := f.Copy(dest); err != nil { if err := f.Copy(dest); err != nil {
t.Fatalf("COPY FAILED: %s", err) t.Fatalf("copying test file failed: %s", err)
} }
} }
@ -73,8 +73,7 @@ func TestIndexRelated(t *testing.T) {
} }
}) })
//TODO this test MUST run before PR 1151 can be merged t.Run("apple-test-2.jpg", func(t *testing.T) {
/*t.Run("/apple-test-2.jpg", func(t *testing.T) {
conf := config.TestConfig() conf := config.TestConfig()
testFile, err := NewMediaFile("testdata/apple-test-2.jpg") testFile, err := NewMediaFile("testdata/apple-test-2.jpg")
@ -96,7 +95,7 @@ func TestIndexRelated(t *testing.T) {
dest := filepath.Join(testPath, f.BaseName()) dest := filepath.Join(testPath, f.BaseName())
if err := f.Copy(dest); err != nil { if err := f.Copy(dest); err != nil {
t.Fatalf("COPY FAILED: %s", err) t.Fatalf("copying test file failed: %s", err)
} }
} }
@ -131,13 +130,12 @@ func TestIndexRelated(t *testing.T) {
} else { } else {
assert.Equal(t, "Botanischer Garten", photo.PhotoTitle) assert.Equal(t, "Botanischer Garten", photo.PhotoTitle)
assert.Equal(t, "Tulpen am See", photo.PhotoDescription) assert.Equal(t, "Tulpen am See", photo.PhotoDescription)
assert.Contains(t, photo.Details.Keywords, "apple")
assert.Contains(t, photo.Details.Keywords, "green")
assert.Contains(t, photo.Details.Keywords, "krokus") assert.Contains(t, photo.Details.Keywords, "krokus")
assert.Contains(t, photo.Details.Keywords, "blume") assert.Contains(t, photo.Details.Keywords, "blume")
assert.Contains(t, photo.Details.Keywords, "schöne wiese") assert.Contains(t, photo.Details.Keywords, "schöne")
assert.Contains(t, photo.Details.Keywords, "wiese")
assert.Equal(t, "2021-03-24 12:07:29 +0000 UTC", photo.TakenAt.String()) assert.Equal(t, "2021-03-24 12:07:29 +0000 UTC", photo.TakenAt.String())
assert.Equal(t, "xmp", photo.TakenSrc) assert.Equal(t, "xmp", photo.TakenSrc)
} }
})*/ })
} }