Metadata: Add support for XMP sidecar CreateDate and Keywords #1151
This commit is contained in:
parent
70c28054b5
commit
8c214a07cd
4 changed files with 37 additions and 20 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
})*/
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue