2020-01-07 17:36:49 +01:00
|
|
|
package meta
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2020-05-15 15:29:56 +02:00
|
|
|
"path/filepath"
|
2020-07-13 10:41:45 +02:00
|
|
|
"runtime/debug"
|
2022-10-31 16:46:20 +01:00
|
|
|
"time"
|
2020-05-15 15:29:56 +02:00
|
|
|
|
2022-07-06 23:01:54 +02:00
|
|
|
"github.com/photoprism/photoprism/pkg/fs"
|
|
|
|
|
2022-04-15 09:42:07 +02:00
|
|
|
"github.com/photoprism/photoprism/pkg/clean"
|
2020-01-07 17:36:49 +01:00
|
|
|
)
|
|
|
|
|
2020-01-07 18:13:53 +01:00
|
|
|
// XMP parses an XMP file and returns a Data struct.
|
2020-05-13 20:53:15 +02:00
|
|
|
func XMP(fileName string) (data Data, err error) {
|
|
|
|
err = data.XMP(fileName)
|
|
|
|
|
|
|
|
return data, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// XMP parses an XMP file and returns a Data struct.
|
|
|
|
func (data *Data) XMP(fileName string) (err error) {
|
2020-01-07 17:36:49 +01:00
|
|
|
defer func() {
|
|
|
|
if e := recover(); e != nil {
|
2022-04-15 09:42:07 +02:00
|
|
|
err = fmt.Errorf("metadata: %s in %s (xmp panic)\nstack: %s", e, clean.Log(filepath.Base(fileName)), debug.Stack())
|
2020-01-07 17:36:49 +01:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2022-07-06 23:01:54 +02:00
|
|
|
// Resolve file name e.g. in case it's a symlink.
|
|
|
|
if fileName, err = fs.Resolve(fileName); err != nil {
|
|
|
|
return fmt.Errorf("metadata: %s %s (xmp)", err, clean.Log(filepath.Base(fileName)))
|
|
|
|
}
|
|
|
|
|
2020-01-13 23:14:10 +01:00
|
|
|
doc := XmpDocument{}
|
2020-01-07 17:36:49 +01:00
|
|
|
|
2022-07-06 23:01:54 +02:00
|
|
|
if err = doc.Load(fileName); err != nil {
|
2022-04-15 09:42:07 +02:00
|
|
|
return fmt.Errorf("metadata: cannot read %s (xmp)", clean.Log(filepath.Base(fileName)))
|
2020-01-07 17:36:49 +01:00
|
|
|
}
|
|
|
|
|
2020-05-13 20:53:15 +02:00
|
|
|
if doc.Title() != "" {
|
|
|
|
data.Title = doc.Title()
|
|
|
|
}
|
|
|
|
|
|
|
|
if doc.Artist() != "" {
|
|
|
|
data.Artist = doc.Artist()
|
|
|
|
}
|
|
|
|
|
|
|
|
if doc.Description() != "" {
|
|
|
|
data.Description = doc.Description()
|
|
|
|
}
|
|
|
|
|
|
|
|
if doc.Copyright() != "" {
|
|
|
|
data.Copyright = doc.Copyright()
|
|
|
|
}
|
|
|
|
|
|
|
|
if doc.CameraMake() != "" {
|
|
|
|
data.CameraMake = doc.CameraMake()
|
|
|
|
}
|
|
|
|
|
|
|
|
if doc.CameraModel() != "" {
|
|
|
|
data.CameraModel = doc.CameraModel()
|
|
|
|
}
|
|
|
|
|
|
|
|
if doc.LensModel() != "" {
|
|
|
|
data.LensModel = doc.LensModel()
|
|
|
|
}
|
2020-01-07 17:36:49 +01:00
|
|
|
|
2022-10-31 16:46:20 +01:00
|
|
|
if takenAt := doc.TakenAt(data.TimeZone); !takenAt.IsZero() {
|
|
|
|
data.TakenAt = takenAt.UTC()
|
|
|
|
if data.TimeZone == "" {
|
|
|
|
data.TimeZone = time.UTC.String()
|
|
|
|
}
|
2021-04-26 13:54:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(doc.Keywords()) != 0 {
|
|
|
|
data.AddKeywords(doc.Keywords())
|
|
|
|
}
|
|
|
|
|
2023-07-23 15:43:32 +02:00
|
|
|
data.Favorite = doc.Favorite()
|
|
|
|
|
2020-05-13 20:53:15 +02:00
|
|
|
return nil
|
2020-01-07 17:36:49 +01:00
|
|
|
}
|