Live Photos: Only flag actual Live and Motion Photos as "Live" #5089

Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
Michael Mayer 2025-07-06 11:07:25 +02:00
parent 57349bdb99
commit f80ac62e6b
12 changed files with 499 additions and 292 deletions

View file

@ -245,6 +245,54 @@ func (m *Photo) GetUID() string {
return m.PhotoUID
}
// MediaType returns the current PhotoType as media.Type.
func (m *Photo) MediaType() media.Type {
return media.Type(m.PhotoType)
}
// HasMediaType checks if the photo has any of the specified media types.
func (m *Photo) HasMediaType(types ...media.Type) bool {
mediaType := m.MediaType()
for _, t := range types {
if mediaType == t {
return true
}
}
return false
}
// SetMediaType sets a new media type if its priority is higher than that of the current type.
func (m *Photo) SetMediaType(newType media.Type, typeSrc string) {
// Only allow a new main media type to be set.
if !newType.IsMain() || newType.Equal(m.PhotoType) {
return
}
// Get current media type.
currentType := m.MediaType()
// Do not change the type if the source priority is lower than the current one.
if SrcPriority[typeSrc] < SrcPriority[m.TypeSrc] && currentType.IsMain() {
return
}
// Do not automatically change a higher priority type to a lower one.
if SrcPriority[typeSrc] <= SrcPriority[SrcFile] && media.Priority[newType] < media.Priority[currentType] {
return
}
// Set new type and type source.
m.PhotoType = newType.String()
m.TypeSrc = typeSrc
// Write a debug log containing the old and new media type.
log.Debugf("photo: changed type of %s from %s to %s", m.String(), currentType.String(), newType.String())
return
}
// String returns the id or name as string.
func (m *Photo) String() string {
if m == nil {

View file

@ -33,13 +33,13 @@ var PhotoFixtures = PhotoMap{
PhotoUID: "ps6sg6be2lvl0yh7",
TakenAt: time.Date(2008, 7, 1, 10, 0, 0, 0, time.UTC),
TakenAtLocal: time.Date(2008, 7, 1, 12, 0, 0, 0, time.UTC),
TakenSrc: "meta",
PhotoType: "image",
TypeSrc: "",
TakenSrc: SrcMeta,
PhotoType: MediaImage,
TypeSrc: SrcAuto,
PhotoTitle: "Lake / 2790",
TitleSrc: "",
TitleSrc: SrcAuto,
PhotoCaption: "photo caption lake",
CaptionSrc: "meta",
CaptionSrc: SrcMeta,
PhotoPath: "2790/07",
PhotoName: "27900704_070228_D6D51B6C",
OriginalName: "Vacation/exampleFileNameOriginal",
@ -71,7 +71,7 @@ var PhotoFixtures = PhotoMap{
Camera: CameraFixtures.Pointer("canon-eos-6d"),
CameraID: CameraFixtures.Pointer("canon-eos-6d").ID,
CameraSerial: "",
CameraSrc: "meta",
CameraSrc: SrcMeta,
Lens: LensFixtures.Pointer("lens-f-380"),
LensID: LensFixtures.Pointer("lens-f-380").ID,
Details: DetailsFixtures.Pointer("lake", 1000000),
@ -100,13 +100,13 @@ var PhotoFixtures = PhotoMap{
PhotoUID: "ps6sg6be2lvl0yh8",
TakenAt: time.Date(2006, 1, 1, 2, 0, 0, 0, time.UTC),
TakenAtLocal: time.Date(2006, 1, 1, 2, 0, 0, 0, time.UTC),
TakenSrc: "meta",
PhotoType: "raw",
TypeSrc: "",
TakenSrc: SrcMeta,
PhotoType: MediaRaw,
TypeSrc: SrcAuto,
PhotoTitle: "",
TitleSrc: "",
TitleSrc: SrcAuto,
PhotoCaption: "photo caption non-photographic",
CaptionSrc: "",
CaptionSrc: SrcAuto,
PhotoPath: "2790/02",
PhotoName: "Photo01",
OriginalName: "",
@ -117,7 +117,7 @@ var PhotoFixtures = PhotoMap{
TimeZone: "Europe/Berlin",
Place: PlaceFixtures.Pointer("Germany"),
PlaceID: PlaceFixtures.Pointer("Germany").ID,
PlaceSrc: "manual",
PlaceSrc: SrcManual,
Cell: CellFixtures.Pointer("Neckarbrücke"),
CellID: CellFixtures.Pointer("Neckarbrücke").ID,
CellAccuracy: 0,
@ -161,13 +161,13 @@ var PhotoFixtures = PhotoMap{
PhotoUID: "ps6sg6be2lvl0yh9",
TakenAt: time.Date(1990, 3, 2, 0, 0, 0, 0, time.UTC),
TakenAtLocal: time.Date(1990, 3, 2, 0, 0, 0, 0, time.UTC),
TakenSrc: "manual",
PhotoType: "image",
TypeSrc: "",
TakenSrc: SrcManual,
PhotoType: MediaImage,
TypeSrc: SrcAuto,
PhotoTitle: "",
TitleSrc: "",
TitleSrc: SrcAuto,
PhotoCaption: "",
CaptionSrc: "",
CaptionSrc: SrcAuto,
PhotoPath: "London",
PhotoName: "bridge1",
OriginalName: "",
@ -178,7 +178,7 @@ var PhotoFixtures = PhotoMap{
TimeZone: "Local",
Place: &UnknownPlace,
PlaceID: UnknownPlace.ID,
PlaceSrc: "",
PlaceSrc: SrcAuto,
Cell: &UnknownLocation,
CellID: UnknownLocation.ID,
CellAccuracy: 0,
@ -198,7 +198,7 @@ var PhotoFixtures = PhotoMap{
Camera: CameraFixtures.Pointer("canon-eos-6d"),
CameraID: CameraFixtures.Pointer("canon-eos-6d").ID,
CameraSerial: "",
CameraSrc: "",
CameraSrc: SrcAuto,
Lens: LensFixtures.Pointer("lens-f-380"),
LensID: LensFixtures.Pointer("lens-f-380").ID,
Details: DetailsFixtures.Pointer("lake", 1000002),
@ -220,8 +220,8 @@ var PhotoFixtures = PhotoMap{
PhotoUID: "ps6sg6be2lvl0yh0",
TakenAt: time.Date(1990, 4, 18, 1, 0, 0, 0, time.UTC),
TakenAtLocal: time.Date(1990, 4, 18, 1, 0, 0, 0, time.UTC),
TakenSrc: "meta",
PhotoType: "video",
TakenSrc: SrcMeta,
PhotoType: MediaVideo,
PhotoDuration: time.Hour * 2,
TypeSrc: "",
PhotoTitle: "",
@ -238,7 +238,7 @@ var PhotoFixtures = PhotoMap{
TimeZone: "Local",
Place: CellFixtures.Pointer("caravan park").Place,
PlaceID: CellFixtures.Pointer("caravan park").Place.ID,
PlaceSrc: "meta",
PlaceSrc: SrcMeta,
Cell: CellFixtures.Pointer("caravan park"),
CellID: CellFixtures.Pointer("caravan park").ID,
CellAccuracy: 0,
@ -1358,8 +1358,8 @@ var PhotoFixtures = PhotoMap{
TakenAt: time.Date(2001, 1, 1, 7, 0, 0, 0, time.UTC),
TakenAtLocal: time.Date(2001, 1, 1, 7, 0, 0, 0, time.UTC),
TakenSrc: "",
PhotoType: "image",
TypeSrc: "",
PhotoType: MediaImage,
TypeSrc: SrcAuto,
PhotoTitle: "Lake / 2001",
TitleSrc: "",
PhotoCaption: "",
@ -1417,8 +1417,8 @@ var PhotoFixtures = PhotoMap{
TakenAt: time.Date(2020, 11, 11, 9, 7, 18, 0, time.UTC),
TakenAtLocal: time.Date(2020, 11, 11, 9, 7, 18, 0, time.UTC),
TakenSrc: SrcMeta,
PhotoType: "image",
TypeSrc: "",
PhotoType: MediaImage,
TypeSrc: SrcAuto,
PhotoTitle: "ForMerge",
TitleSrc: SrcManual,
PhotoCaption: "",
@ -1478,8 +1478,8 @@ var PhotoFixtures = PhotoMap{
TakenAt: time.Date(2020, 11, 11, 9, 7, 18, 0, time.UTC),
TakenAtLocal: time.Date(2020, 11, 11, 9, 7, 18, 0, time.UTC),
TakenSrc: SrcMeta,
PhotoType: "raw",
TypeSrc: "",
PhotoType: MediaRaw,
TypeSrc: SrcAuto,
PhotoTitle: "ForMerge2",
TitleSrc: SrcManual,
PhotoCaption: "",
@ -1539,8 +1539,8 @@ var PhotoFixtures = PhotoMap{
TakenAt: time.Date(2007, 1, 11, 9, 7, 18, 0, time.UTC),
TakenAtLocal: time.Date(2007, 1, 11, 9, 7, 18, 0, time.UTC),
TakenSrc: SrcMeta,
PhotoType: "image",
TypeSrc: "",
PhotoType: MediaImage,
TypeSrc: SrcAuto,
PhotoTitle: "photowitheditedatdate",
TitleSrc: SrcManual,
PhotoCaption: "",
@ -1602,8 +1602,8 @@ var PhotoFixtures = PhotoMap{
TakenAt: time.Date(2007, 1, 11, 9, 7, 18, 0, time.UTC),
TakenAtLocal: time.Date(2007, 1, 11, 9, 7, 18, 0, time.UTC),
TakenSrc: SrcMeta,
PhotoType: "image",
TypeSrc: "",
PhotoType: MediaImage,
TypeSrc: SrcAuto,
PhotoTitle: "phototobebatchapproved",
TitleSrc: SrcAuto,
PhotoCaption: "",
@ -1663,8 +1663,8 @@ var PhotoFixtures = PhotoMap{
TakenAt: time.Date(2000, 12, 11, 9, 7, 18, 0, time.UTC),
TakenAtLocal: time.Date(2000, 12, 11, 4, 7, 18, 0, time.UTC),
TakenSrc: SrcMeta,
PhotoType: "live",
TypeSrc: "",
PhotoType: MediaLive,
TypeSrc: SrcFile,
PhotoTitle: "phototobebatchapproved2",
TitleSrc: SrcName,
PhotoCaption: "",

View file

@ -9,6 +9,7 @@ import (
"github.com/photoprism/photoprism/internal/ai/classify"
"github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/pkg/media"
"github.com/photoprism/photoprism/pkg/time/tz"
)
@ -72,6 +73,90 @@ func TestSavePhotoForm(t *testing.T) {
})
}
func TestPhoto_HasUID(t *testing.T) {
t.Run("True", func(t *testing.T) {
m := PhotoFixtures.Get("Photo01")
assert.True(t, m.HasID())
assert.True(t, m.HasUID())
})
t.Run("False", func(t *testing.T) {
m := Photo{}
assert.False(t, m.HasID())
assert.False(t, m.HasUID())
})
}
func TestPhoto_GetID(t *testing.T) {
t.Run("Success", func(t *testing.T) {
m := PhotoFixtures.Get("Photo01")
assert.Equal(t, uint(1000001), m.GetID())
})
}
func TestPhoto_MediaType(t *testing.T) {
t.Run("Image", func(t *testing.T) {
m := PhotoFixtures.Get("19800101_000002_D640C559")
assert.Equal(t, media.Image, m.MediaType())
})
t.Run("Live", func(t *testing.T) {
m := PhotoFixtures.Get("Photo27")
assert.Equal(t, media.Live, m.MediaType())
})
}
func TestPhoto_HasMediaType(t *testing.T) {
t.Run("Image", func(t *testing.T) {
m := PhotoFixtures.Get("19800101_000002_D640C559")
assert.True(t, m.HasMediaType(media.Image))
assert.True(t, m.HasMediaType(media.Image, media.Video, media.Live))
assert.False(t, m.HasMediaType(media.Video, media.Live))
assert.False(t, m.HasMediaType())
})
t.Run("Live", func(t *testing.T) {
m := PhotoFixtures.Get("Photo27")
assert.True(t, m.HasMediaType(media.Live))
assert.True(t, m.HasMediaType(media.Image, media.Video, media.Live))
assert.False(t, m.HasMediaType(media.Image, media.Animated))
assert.False(t, m.HasMediaType())
})
}
func TestPhoto_SetMediaType(t *testing.T) {
t.Run("Image", func(t *testing.T) {
m := PhotoFixtures.Get("19800101_000002_D640C559")
assert.Equal(t, media.Image, m.MediaType())
assert.Equal(t, SrcAuto, m.TypeSrc)
m.SetMediaType(media.Video, SrcAuto)
assert.Equal(t, media.Video, m.MediaType())
assert.Equal(t, SrcAuto, m.TypeSrc)
m.SetMediaType(media.Live, SrcAuto)
assert.Equal(t, media.Live, m.MediaType())
assert.Equal(t, SrcAuto, m.TypeSrc)
m.SetMediaType(media.Video, SrcAuto)
assert.Equal(t, media.Live, m.MediaType())
assert.Equal(t, SrcAuto, m.TypeSrc)
m.SetMediaType(media.Image, SrcAuto)
assert.Equal(t, media.Live, m.MediaType())
assert.Equal(t, SrcAuto, m.TypeSrc)
m.SetMediaType("", SrcAuto)
assert.Equal(t, media.Live, m.MediaType())
assert.Equal(t, SrcAuto, m.TypeSrc)
m.SetMediaType(media.Video, SrcManual)
assert.Equal(t, media.Video, m.MediaType())
assert.Equal(t, SrcManual, m.TypeSrc)
})
t.Run("Live", func(t *testing.T) {
m := PhotoFixtures.Get("Photo27")
assert.Equal(t, media.Live, m.MediaType())
m.SetMediaType(media.Image, SrcAuto)
assert.Equal(t, media.Live, m.MediaType())
assert.Equal(t, SrcFile, m.TypeSrc)
m.SetMediaType(media.Image, SrcManual)
assert.Equal(t, media.Image, m.MediaType())
assert.Equal(t, SrcManual, m.TypeSrc)
})
}
func TestPhoto_SaveLabels(t *testing.T) {
t.Run("NewPhoto", func(t *testing.T) {
photo := Photo{
@ -125,26 +210,6 @@ func TestPhoto_SaveLabels(t *testing.T) {
})
}
func TestPhoto_HasUID(t *testing.T) {
t.Run("True", func(t *testing.T) {
m := PhotoFixtures.Get("Photo01")
assert.True(t, m.HasID())
assert.True(t, m.HasUID())
})
t.Run("False", func(t *testing.T) {
m := Photo{}
assert.False(t, m.HasID())
assert.False(t, m.HasUID())
})
}
func TestPhoto_GetID(t *testing.T) {
t.Run("Success", func(t *testing.T) {
m := PhotoFixtures.Get("Photo01")
assert.Equal(t, uint(1000001), m.GetID())
})
}
func TestPhoto_ClassifyLabels(t *testing.T) {
t.Run("NewPhoto", func(t *testing.T) {
m := PhotoFixtures.Get("Photo19")

View file

@ -9,6 +9,7 @@ const (
SrcAuto = "" // Prio 1
SrcDefault = "default" // Prio 1
SrcEstimate = "estimate" // Prio 2
SrcFile = "file" // Prio 2
SrcName = "name" // Prio 4
SrcYaml = "yaml" // Prio 8
SrcOIDC = "oidc" // Prio 8
@ -40,6 +41,7 @@ var SrcPriority = Priorities{
SrcAuto: 1,
SrcDefault: 1,
SrcEstimate: 2,
SrcFile: 2,
SrcName: 4,
SrcYaml: 8,
SrcOIDC: 8,

View file

@ -17,7 +17,6 @@ import (
"github.com/photoprism/photoprism/pkg/clean"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/pkg/media"
"github.com/photoprism/photoprism/pkg/media/video"
"github.com/photoprism/photoprism/pkg/rnd"
"github.com/photoprism/photoprism/pkg/time/tz"
"github.com/photoprism/photoprism/pkg/txt"
@ -433,12 +432,9 @@ func (ind *Index) UserMediaFile(m *MediaFile, o IndexOptions, originalName, phot
// Change file and photo type to "live" if the file has a video embedded.
file.FileVideo = true
file.MediaType = entity.MediaLive
if photo.TypeSrc == entity.SrcAuto {
photo.PhotoType = entity.MediaLive
}
} else if photo.TypeSrc == entity.SrcAuto && photo.PhotoType == entity.MediaLive {
// Image does not include a compatible video.
photo.PhotoType = entity.MediaImage
// Set photo media type to "live".
photo.SetMediaType(media.Live, entity.SrcFile)
}
if file.OriginalName == "" && filepath.Base(file.FileName) != data.FileName {
@ -459,9 +455,14 @@ func (ind *Index) UserMediaFile(m *MediaFile, o IndexOptions, originalName, phot
}
}
// Change the photo type to animated if it is an animated PNG.
if photo.TypeSrc == entity.SrcAuto && photo.PhotoType == entity.MediaImage && m.IsAnimatedImage() {
photo.PhotoType = entity.MediaAnimated
// If the photo contains an animation or has a video,
// change the photo type from image to animated or live.
if photo.HasMediaType(media.Image) {
if m.IsAnimatedImage() {
photo.SetMediaType(media.Animated, entity.SrcAuto)
} else if m.IsLive() {
photo.SetMediaType(media.Live, entity.SrcAuto)
}
}
case m.IsXMP():
if data, dataErr := meta.XMP(m.FileName()); dataErr == nil {
@ -554,12 +555,12 @@ func (ind *Index) UserMediaFile(m *MediaFile, o IndexOptions, originalName, phot
// Change file and photo type to "live" if the file has a video embedded.
file.FileVideo = true
file.MediaType = entity.MediaLive
if photo.TypeSrc == entity.SrcAuto {
photo.PhotoType = entity.MediaLive
}
} else if photo.TypeSrc == entity.SrcAuto && photo.PhotoType == entity.MediaLive {
// HEIC does not include a compatible video.
photo.PhotoType = entity.MediaImage
// If the file also contains a video, set photo media type to "live".
photo.SetMediaType(media.Live, entity.SrcFile)
} else {
// If the file does not contain a video, set the media type to "image".
photo.SetMediaType(media.Image, entity.SrcAuto)
}
// Set photo resolution based on the largest media file.
@ -573,15 +574,15 @@ func (ind *Index) UserMediaFile(m *MediaFile, o IndexOptions, originalName, phot
}
// Update photo type if an image and not manually modified.
if photo.TypeSrc == entity.SrcAuto && photo.PhotoType == entity.MediaImage {
if photo.HasMediaType(media.Image) {
if m.IsAnimatedImage() {
photo.PhotoType = entity.MediaAnimated
photo.SetMediaType(media.Animated, entity.SrcAuto)
} else if m.IsRaw() {
photo.PhotoType = entity.MediaRaw
photo.SetMediaType(media.Raw, entity.SrcAuto)
} else if m.IsLive() {
photo.PhotoType = entity.MediaLive
photo.SetMediaType(media.Live, entity.SrcAuto)
} else if m.IsVector() {
photo.PhotoType = entity.MediaVector
photo.SetMediaType(media.Vector, entity.SrcAuto)
}
}
case m.IsVector():
@ -637,10 +638,8 @@ func (ind *Index) UserMediaFile(m *MediaFile, o IndexOptions, originalName, phot
}
}
// Update photo type if not manually modified.
if photo.TypeSrc == entity.SrcAuto {
photo.PhotoType = entity.MediaVector
}
// Set photo media type to "vector".
photo.SetMediaType(media.Vector, entity.SrcAuto)
case m.IsDocument():
if data := m.MetaData(); data.Error == nil {
photo.SetTitle(data.Title, entity.SrcMeta)
@ -691,10 +690,8 @@ func (ind *Index) UserMediaFile(m *MediaFile, o IndexOptions, originalName, phot
}
}
// Update photo type if not manually modified.
if photo.TypeSrc == entity.SrcAuto {
photo.PhotoType = entity.MediaDocument
}
// Set photo media type to "document".
photo.SetMediaType(media.Document, entity.SrcAuto)
case m.IsVideo():
if data := m.MetaData(); data.Error == nil {
photo.SetTitle(data.Title, entity.SrcMeta)
@ -759,13 +756,11 @@ func (ind *Index) UserMediaFile(m *MediaFile, o IndexOptions, originalName, phot
photo.SetExposure(m.FocalLength(), m.FNumber(), m.Iso(), m.Exposure(), entity.SrcMeta)
}
if photo.TypeSrc == entity.SrcAuto {
// Update photo type only if not manually modified.
if file.FileDuration == 0 || file.FileDuration > video.LiveDuration {
photo.PhotoType = entity.MediaVideo
} else {
photo.PhotoType = entity.MediaLive
}
// Set photo media type to "live" or "video".
if m.IsLive() {
photo.SetMediaType(media.Live, entity.SrcAuto)
} else {
photo.SetMediaType(media.Video, entity.SrcAuto)
}
// Set the video dimensions from the primary image if it could not be determined from the video metadata.
@ -910,27 +905,28 @@ func (ind *Index) UserMediaFile(m *MediaFile, o IndexOptions, originalName, phot
})
}
if photo.PhotoType == entity.MediaAnimated {
switch photo.MediaType() {
case media.Animated:
event.Publish("count.animated", event.Data{
"count": 1,
})
} else if photo.PhotoType == entity.MediaLive {
case media.Live:
event.Publish("count.live", event.Data{
"count": 1,
})
} else if photo.PhotoType == entity.MediaAudio {
case media.Audio:
event.Publish("count.audio", event.Data{
"count": 1,
})
} else if photo.PhotoType == entity.MediaVideo {
case media.Video:
event.Publish("count.videos", event.Data{
"count": 1,
})
} else if photo.PhotoType == entity.MediaDocument {
case media.Document:
event.Publish("count.documents", event.Data{
"count": 1,
})
} else {
default:
event.Publish("count.photos", event.Data{
"count": 1,
})
@ -1038,7 +1034,7 @@ func (ind *Index) UserMediaFile(m *MediaFile, o IndexOptions, originalName, phot
}
// Update related video files so they are properly grouped with the primary image in search results.
if (photo.PhotoType == entity.MediaVideo || photo.PhotoType == entity.MediaLive) && file.FilePrimary {
if photo.HasMediaType(media.Video, media.Live) && file.FilePrimary {
if updateErr := file.UpdateVideoInfos(); updateErr != nil {
log.Errorf("index: %s in %s (update video infos)", updateErr, logName)
}

View file

@ -994,7 +994,7 @@ func (m *MediaFile) IsVideo() bool {
// IsSidecar checks if the file is a metadata sidecar file, independent of the storage location.
func (m *MediaFile) IsSidecar() bool {
return !m.Media().Main()
return !m.Media().IsMain()
}
// IsArchive returns true if this is an archive file.
@ -1064,12 +1064,19 @@ func (m *MediaFile) IsImageNative() bool {
// IsLive checks if the file is a live photo.
func (m *MediaFile) IsLive() bool {
if m.IsHeic() {
return fs.VideoMov.FindFirst(m.FileName(), []string{}, Config().OriginalsPath(), false) != ""
if !m.InOriginals() {
return false
}
if m.IsVideo() {
return fs.ImageHeic.FindFirst(m.FileName(), []string{}, Config().OriginalsPath(), false) != ""
if fs.ImageHeic.FindFirst(m.FileName(), []string{}, Config().OriginalsPath(), false) != "" ||
fs.ImageJpeg.FindFirst(m.FileName(), []string{}, Config().OriginalsPath(), false) != "" {
return true
}
} else if m.IsHeic() || m.IsJpeg() {
if fs.VideoMov.FindFirst(m.FileName(), []string{}, Config().OriginalsPath(), false) != "" {
return true
}
}
return m.MetaData().MediaType == media.Live && m.VideoInfo().Compatible

View file

@ -214,7 +214,7 @@ func TestMediaFile_HasTimeAndPlace(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, true, mediaFile.HasTimeAndPlace())
assert.True(t, mediaFile.HasTimeAndPlace())
})
t.Run("/peacock_blue.jpg", func(t *testing.T) {
conf := config.TestConfig()
@ -223,7 +223,7 @@ func TestMediaFile_HasTimeAndPlace(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.HasTimeAndPlace())
assert.False(t, mediaFile.HasTimeAndPlace())
})
}
func TestMediaFile_CameraModel(t *testing.T) {
@ -715,7 +715,7 @@ func TestMediaFile_MimeType(t *testing.T) {
assert.True(t, fs.SameType(header.ContentTypeText, mediaFile.BaseType()))
assert.Equal(t, "text/plain", mediaFile.BaseType())
assert.Equal(t, "text/plain; charset=utf-8", mediaFile.MimeType())
assert.Equal(t, true, mediaFile.HasMimeType("text/plain"))
assert.True(t, mediaFile.HasMimeType("text/plain"))
})
t.Run("iphone_7.json", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/iphone_7.json")
@ -749,7 +749,7 @@ func TestMediaFile_MimeType(t *testing.T) {
assert.True(t, fs.SameType(header.ContentTypeXml, mediaFile.BaseType()))
assert.Equal(t, "text/xml", mediaFile.BaseType())
assert.Equal(t, "text/xml; charset=utf-8", mediaFile.MimeType())
assert.Equal(t, true, mediaFile.HasMimeType("text/xml"))
assert.True(t, mediaFile.HasMimeType("text/xml"))
})
t.Run("earth.mov", func(t *testing.T) {
if f, err := NewMediaFile(filepath.Join(c.ExamplesPath(), "earth.mov")); err != nil {
@ -819,16 +819,16 @@ func TestMediaFile_Exists(t *testing.T) {
assert.NotNil(t, exists)
assert.True(t, exists.Exists())
assert.Equal(t, true, exists.Ok())
assert.Equal(t, false, exists.Empty())
assert.True(t, exists.Ok())
assert.False(t, exists.Empty())
missing, err := NewMediaFile(c.ExamplesPath() + "/xxz.jpg")
assert.NotNil(t, missing)
assert.Error(t, err)
assert.Equal(t, int64(-1), missing.FileSize())
assert.Equal(t, false, missing.Ok())
assert.Equal(t, true, missing.Empty())
assert.False(t, missing.Ok())
assert.True(t, missing.Empty())
}
func TestMediaFile_SetModTime(t *testing.T) {
@ -967,28 +967,28 @@ func TestMediaFile_IsJpeg(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsJpeg())
assert.False(t, mediaFile.IsJpeg())
})
t.Run("iphone_7.heic", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/iphone_7.heic")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsJpeg())
assert.False(t, mediaFile.IsJpeg())
})
t.Run("canon_eos_6d.dng", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/canon_eos_6d.dng")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsJpeg())
assert.False(t, mediaFile.IsJpeg())
})
t.Run("elephants.jpg", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/elephants.jpg")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, true, mediaFile.IsJpeg())
assert.True(t, mediaFile.IsJpeg())
})
}
@ -1000,28 +1000,28 @@ func TestMediaFile_HasType(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.HasFileType("jpg"))
assert.False(t, mediaFile.HasFileType("jpg"))
})
t.Run("fox.profile0.8bpc.yuv420.avif", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/fox.profile0.8bpc.yuv420.avif")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, true, mediaFile.HasFileType("avif"))
assert.True(t, mediaFile.HasFileType("avif"))
})
t.Run("iphone_7.heic", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/iphone_7.heic")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, true, mediaFile.HasFileType("heic"))
assert.True(t, mediaFile.HasFileType("heic"))
})
t.Run("iphone_7.xmp", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/iphone_7.xmp")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, true, mediaFile.HasFileType("xmp"))
assert.True(t, mediaFile.HasFileType("xmp"))
})
}
@ -1033,28 +1033,28 @@ func TestMediaFile_IsHeic(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsHeic())
assert.False(t, mediaFile.IsHeic())
})
t.Run("iphone_7.heic", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/iphone_7.heic")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, true, mediaFile.IsHeic())
assert.True(t, mediaFile.IsHeic())
})
t.Run("canon_eos_6d.dng", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/canon_eos_6d.dng")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsHeic())
assert.False(t, mediaFile.IsHeic())
})
t.Run("elephants.jpg", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/elephants.jpg")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsHeic())
assert.False(t, mediaFile.IsHeic())
})
}
@ -1066,14 +1066,14 @@ func TestMediaFile_IsRaw(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsRaw())
assert.False(t, mediaFile.IsRaw())
})
t.Run("iphone_7.heic", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/iphone_7.heic")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsRaw())
assert.False(t, mediaFile.IsRaw())
})
t.Run("canon_eos_6d.dng", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/canon_eos_6d.dng")
@ -1081,14 +1081,14 @@ func TestMediaFile_IsRaw(t *testing.T) {
t.Fatal(err)
}
assert.Equal(t, true, mediaFile.IsRaw())
assert.True(t, mediaFile.IsRaw())
})
t.Run("elephants.jpg", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/elephants.jpg")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsRaw())
assert.False(t, mediaFile.IsRaw())
})
}
@ -1100,7 +1100,7 @@ func TestMediaFile_IsPng(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsPng())
assert.False(t, mediaFile.IsPng())
})
t.Run("tweethog.png", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/tweethog.png")
@ -1111,7 +1111,7 @@ func TestMediaFile_IsPng(t *testing.T) {
assert.Equal(t, fs.ImagePng, mediaFile.FileType())
assert.Equal(t, "image/png", mediaFile.MimeType())
assert.Equal(t, true, mediaFile.IsPng())
assert.True(t, mediaFile.IsPng())
})
}
@ -1125,7 +1125,7 @@ func TestMediaFile_IsTiff(t *testing.T) {
}
assert.Equal(t, fs.SidecarJson, mediaFile.FileType())
assert.Equal(t, header.ContentTypeJson, mediaFile.MimeType())
assert.Equal(t, false, mediaFile.IsTiff())
assert.False(t, mediaFile.IsTiff())
})
t.Run("purple.tiff", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/purple.tiff")
@ -1134,7 +1134,7 @@ func TestMediaFile_IsTiff(t *testing.T) {
}
assert.Equal(t, fs.ImageTiff, mediaFile.FileType())
assert.Equal(t, "image/tiff", mediaFile.MimeType())
assert.Equal(t, true, mediaFile.IsTiff())
assert.True(t, mediaFile.IsTiff())
})
t.Run("example.tiff", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/example.tif")
@ -1143,7 +1143,7 @@ func TestMediaFile_IsTiff(t *testing.T) {
}
assert.Equal(t, fs.ImageTiff, mediaFile.FileType())
assert.Equal(t, "image/tiff", mediaFile.MimeType())
assert.Equal(t, true, mediaFile.IsTiff())
assert.True(t, mediaFile.IsTiff())
})
}
@ -1155,30 +1155,30 @@ func TestMediaFile_IsImageOther(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsImageOther())
assert.False(t, mediaFile.IsImageOther())
})
t.Run("purple.tiff", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/purple.tiff")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, true, mediaFile.IsImageOther())
assert.True(t, mediaFile.IsImageOther())
})
t.Run("tweethog.png", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/tweethog.png")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsJpeg())
assert.Equal(t, false, mediaFile.IsGif())
assert.Equal(t, true, mediaFile.IsPng())
assert.Equal(t, false, mediaFile.IsBmp())
assert.Equal(t, false, mediaFile.IsWebp())
assert.Equal(t, true, mediaFile.IsImage())
assert.Equal(t, true, mediaFile.IsImageNative())
assert.Equal(t, true, mediaFile.IsImageOther())
assert.Equal(t, false, mediaFile.IsVideo())
assert.Equal(t, true, mediaFile.SkipTranscoding())
assert.False(t, mediaFile.IsJpeg())
assert.False(t, mediaFile.IsGif())
assert.True(t, mediaFile.IsPng())
assert.False(t, mediaFile.IsBmp())
assert.False(t, mediaFile.IsWebp())
assert.True(t, mediaFile.IsImage())
assert.True(t, mediaFile.IsImageNative())
assert.True(t, mediaFile.IsImageOther())
assert.False(t, mediaFile.IsVideo())
assert.True(t, mediaFile.SkipTranscoding())
})
t.Run("yellow_rose-small.bmp", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/yellow_rose-small.bmp")
@ -1187,15 +1187,15 @@ func TestMediaFile_IsImageOther(t *testing.T) {
}
assert.Equal(t, fs.ImageBmp, mediaFile.FileType())
assert.Equal(t, "image/bmp", mediaFile.MimeType())
assert.Equal(t, false, mediaFile.IsJpeg())
assert.Equal(t, false, mediaFile.IsGif())
assert.Equal(t, true, mediaFile.IsBmp())
assert.Equal(t, false, mediaFile.IsWebp())
assert.Equal(t, true, mediaFile.IsImage())
assert.Equal(t, true, mediaFile.IsImageNative())
assert.Equal(t, true, mediaFile.IsImageOther())
assert.Equal(t, false, mediaFile.IsVideo())
assert.Equal(t, true, mediaFile.SkipTranscoding())
assert.False(t, mediaFile.IsJpeg())
assert.False(t, mediaFile.IsGif())
assert.True(t, mediaFile.IsBmp())
assert.False(t, mediaFile.IsWebp())
assert.True(t, mediaFile.IsImage())
assert.True(t, mediaFile.IsImageNative())
assert.True(t, mediaFile.IsImageOther())
assert.False(t, mediaFile.IsVideo())
assert.True(t, mediaFile.SkipTranscoding())
})
t.Run("preloader.gif", func(t *testing.T) {
mediaFile, err := NewMediaFile(c.ExamplesPath() + "/preloader.gif")
@ -1205,15 +1205,15 @@ func TestMediaFile_IsImageOther(t *testing.T) {
assert.Equal(t, fs.ImageGif, mediaFile.FileType())
assert.Equal(t, "image/gif", mediaFile.MimeType())
assert.Equal(t, false, mediaFile.IsJpeg())
assert.Equal(t, true, mediaFile.IsGif())
assert.Equal(t, false, mediaFile.IsBmp())
assert.Equal(t, false, mediaFile.IsWebp())
assert.Equal(t, true, mediaFile.IsImage())
assert.Equal(t, true, mediaFile.IsImageNative())
assert.Equal(t, true, mediaFile.IsImageOther())
assert.Equal(t, false, mediaFile.IsVideo())
assert.Equal(t, true, mediaFile.SkipTranscoding())
assert.False(t, mediaFile.IsJpeg())
assert.True(t, mediaFile.IsGif())
assert.False(t, mediaFile.IsBmp())
assert.False(t, mediaFile.IsWebp())
assert.True(t, mediaFile.IsImage())
assert.True(t, mediaFile.IsImageNative())
assert.True(t, mediaFile.IsImageOther())
assert.False(t, mediaFile.IsVideo())
assert.True(t, mediaFile.SkipTranscoding())
})
t.Run("norway-kjetil-moe.webp", func(t *testing.T) {
mediaFile, err := NewMediaFile("testdata/norway-kjetil-moe.webp")
@ -1224,15 +1224,15 @@ func TestMediaFile_IsImageOther(t *testing.T) {
assert.Equal(t, fs.ImageWebp, mediaFile.FileType())
assert.Equal(t, header.ContentTypeWebp, mediaFile.MimeType())
assert.Equal(t, false, mediaFile.IsJpeg())
assert.Equal(t, false, mediaFile.IsGif())
assert.Equal(t, false, mediaFile.IsBmp())
assert.Equal(t, true, mediaFile.IsWebp())
assert.Equal(t, true, mediaFile.IsImage())
assert.Equal(t, true, mediaFile.IsImageNative())
assert.Equal(t, true, mediaFile.IsImageOther())
assert.Equal(t, false, mediaFile.IsVideo())
assert.Equal(t, true, mediaFile.SkipTranscoding())
assert.False(t, mediaFile.IsJpeg())
assert.False(t, mediaFile.IsGif())
assert.False(t, mediaFile.IsBmp())
assert.True(t, mediaFile.IsWebp())
assert.True(t, mediaFile.IsImage())
assert.True(t, mediaFile.IsImageNative())
assert.True(t, mediaFile.IsImageOther())
assert.False(t, mediaFile.IsVideo())
assert.True(t, mediaFile.SkipTranscoding())
})
}
@ -1318,19 +1318,19 @@ func TestMediaFile_IsSidecar(t *testing.T) {
t.Run("example.zip", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/example.zip")
assert.Nil(t, err)
assert.Equal(t, true, mediaFile.IsArchive())
assert.True(t, mediaFile.IsArchive())
})
t.Run("iphone_7.xmp", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/iphone_7.xmp")
assert.Nil(t, err)
assert.Equal(t, true, mediaFile.IsSidecar())
assert.True(t, mediaFile.IsSidecar())
})
t.Run("IMG_4120.AAE", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/IMG_4120.AAE")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, true, mediaFile.IsSidecar())
assert.True(t, mediaFile.IsSidecar())
})
t.Run("test.xml", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/test.xml")
@ -1338,7 +1338,7 @@ func TestMediaFile_IsSidecar(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, true, mediaFile.IsSidecar())
assert.True(t, mediaFile.IsSidecar())
})
t.Run("test.txt", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/test.txt")
@ -1346,7 +1346,7 @@ func TestMediaFile_IsSidecar(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, true, mediaFile.IsSidecar())
assert.True(t, mediaFile.IsSidecar())
})
t.Run("test.yml", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/test.yml")
@ -1354,7 +1354,7 @@ func TestMediaFile_IsSidecar(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, true, mediaFile.IsSidecar())
assert.True(t, mediaFile.IsSidecar())
})
t.Run("test.md", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/test.md")
@ -1362,7 +1362,7 @@ func TestMediaFile_IsSidecar(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, true, mediaFile.IsSidecar())
assert.True(t, mediaFile.IsSidecar())
})
t.Run("canon_eos_6d.dng", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/canon_eos_6d.dng")
@ -1370,7 +1370,7 @@ func TestMediaFile_IsSidecar(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsSidecar())
assert.False(t, mediaFile.IsSidecar())
})
}
@ -1379,19 +1379,19 @@ func TestMediaFile_IsArchive(t *testing.T) {
t.Run("example.zip", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/example.zip")
assert.Nil(t, err)
assert.Equal(t, true, mediaFile.IsArchive())
assert.True(t, mediaFile.IsArchive())
})
t.Run("iphone_7.xmp", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/iphone_7.xmp")
assert.Nil(t, err)
assert.Equal(t, false, mediaFile.IsArchive())
assert.False(t, mediaFile.IsArchive())
})
t.Run("IMG_4120.AAE", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/IMG_4120.AAE")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsArchive())
assert.False(t, mediaFile.IsArchive())
})
t.Run("test.xml", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/test.xml")
@ -1399,7 +1399,7 @@ func TestMediaFile_IsArchive(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsArchive())
assert.False(t, mediaFile.IsArchive())
})
t.Run("test.txt", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/test.txt")
@ -1407,7 +1407,7 @@ func TestMediaFile_IsArchive(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsArchive())
assert.False(t, mediaFile.IsArchive())
})
t.Run("test.yml", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/test.yml")
@ -1415,7 +1415,7 @@ func TestMediaFile_IsArchive(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsArchive())
assert.False(t, mediaFile.IsArchive())
})
t.Run("test.md", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/test.md")
@ -1423,7 +1423,7 @@ func TestMediaFile_IsArchive(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsArchive())
assert.False(t, mediaFile.IsArchive())
})
t.Run("canon_eos_6d.dng", func(t *testing.T) {
mediaFile, err := NewMediaFile(cfg.ExamplesPath() + "/canon_eos_6d.dng")
@ -1431,7 +1431,7 @@ func TestMediaFile_IsArchive(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, mediaFile.IsArchive())
assert.False(t, mediaFile.IsArchive())
})
}
func TestMediaFile_IsImage(t *testing.T) {
@ -1442,43 +1442,43 @@ func TestMediaFile_IsImage(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, f.IsImage())
assert.Equal(t, false, f.IsRaw())
assert.Equal(t, true, f.IsSidecar())
assert.False(t, f.IsImage())
assert.False(t, f.IsRaw())
assert.True(t, f.IsSidecar())
})
t.Run("iphone_7.xmp", func(t *testing.T) {
f, err := NewMediaFile(c.ExamplesPath() + "/iphone_7.xmp")
assert.Nil(t, err)
assert.Equal(t, false, f.IsImage())
assert.Equal(t, false, f.IsRaw())
assert.Equal(t, true, f.IsSidecar())
assert.False(t, f.IsImage())
assert.False(t, f.IsRaw())
assert.True(t, f.IsSidecar())
})
t.Run("iphone_7.heic", func(t *testing.T) {
f, err := NewMediaFile(c.ExamplesPath() + "/iphone_7.heic")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, true, f.IsImage())
assert.Equal(t, false, f.IsRaw())
assert.Equal(t, false, f.IsSidecar())
assert.True(t, f.IsImage())
assert.False(t, f.IsRaw())
assert.False(t, f.IsSidecar())
})
t.Run("canon_eos_6d.dng", func(t *testing.T) {
f, err := NewMediaFile(c.ExamplesPath() + "/canon_eos_6d.dng")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, false, f.IsImage())
assert.Equal(t, true, f.IsRaw())
assert.Equal(t, false, f.IsSidecar())
assert.False(t, f.IsImage())
assert.True(t, f.IsRaw())
assert.False(t, f.IsSidecar())
})
t.Run("elephants.jpg", func(t *testing.T) {
f, err := NewMediaFile(c.ExamplesPath() + "/elephants.jpg")
if err != nil {
t.Fatal(err)
}
assert.Equal(t, true, f.IsImage())
assert.Equal(t, false, f.IsRaw())
assert.Equal(t, false, f.IsSidecar())
assert.True(t, f.IsImage())
assert.False(t, f.IsRaw())
assert.False(t, f.IsSidecar())
})
}
@ -1489,33 +1489,87 @@ func TestMediaFile_IsVideo(t *testing.T) {
if f, err := NewMediaFile(filepath.Join(c.ExamplesPath(), "christmas.mp4")); err != nil {
t.Fatal(err)
} else {
assert.Equal(t, false, f.IsRaw())
assert.Equal(t, false, f.IsImage())
assert.Equal(t, true, f.IsVideo())
assert.Equal(t, false, f.IsJSON())
assert.Equal(t, false, f.IsSidecar())
assert.False(t, f.IsRaw())
assert.False(t, f.IsImage())
assert.True(t, f.IsVideo())
assert.False(t, f.IsJSON())
assert.False(t, f.IsSidecar())
}
})
t.Run("canon_eos_6d.dng", func(t *testing.T) {
if f, err := NewMediaFile(filepath.Join(c.ExamplesPath(), "canon_eos_6d.dng")); err != nil {
t.Fatal(err)
} else {
assert.Equal(t, true, f.IsRaw())
assert.Equal(t, false, f.IsImage())
assert.Equal(t, false, f.IsVideo())
assert.Equal(t, false, f.IsJSON())
assert.Equal(t, false, f.IsSidecar())
assert.True(t, f.IsRaw())
assert.False(t, f.IsImage())
assert.False(t, f.IsVideo())
assert.False(t, f.IsJSON())
assert.False(t, f.IsSidecar())
}
})
t.Run("iphone_7.json", func(t *testing.T) {
if f, err := NewMediaFile(filepath.Join(c.ExamplesPath(), "iphone_7.json")); err != nil {
t.Fatal(err)
} else {
assert.Equal(t, false, f.IsRaw())
assert.Equal(t, false, f.IsImage())
assert.Equal(t, false, f.IsVideo())
assert.Equal(t, true, f.IsJSON())
assert.Equal(t, true, f.IsSidecar())
assert.False(t, f.IsRaw())
assert.False(t, f.IsImage())
assert.False(t, f.IsVideo())
assert.True(t, f.IsJSON())
assert.True(t, f.IsSidecar())
}
})
}
func TestMediaFile_IsLive(t *testing.T) {
c := config.TestConfig()
t.Run("2018-04-12 19_24_49.jpg", func(t *testing.T) {
fileName := fs.Abs("testdata/2018-04-12 19_24_49.jpg")
if f, err := NewMediaFile(fileName); err != nil {
t.Fatal(err)
} else {
assert.False(t, f.IsLive()) // Image is not in originals path.
assert.False(t, f.IsRaw())
assert.True(t, f.IsImage())
assert.False(t, f.IsVideo())
assert.False(t, f.IsJSON())
assert.False(t, f.IsSidecar())
}
})
t.Run("christmas.mp4", func(t *testing.T) {
if f, err := NewMediaFile(filepath.Join(c.ExamplesPath(), "christmas.mp4")); err != nil {
t.Fatal(err)
} else {
assert.False(t, f.IsLive())
assert.False(t, f.IsRaw())
assert.False(t, f.IsImage())
assert.True(t, f.IsVideo())
assert.False(t, f.IsJSON())
assert.False(t, f.IsSidecar())
}
})
t.Run("canon_eos_6d.dng", func(t *testing.T) {
if f, err := NewMediaFile(filepath.Join(c.ExamplesPath(), "canon_eos_6d.dng")); err != nil {
t.Fatal(err)
} else {
assert.False(t, f.IsLive())
assert.True(t, f.IsRaw())
assert.False(t, f.IsImage())
assert.False(t, f.IsVideo())
assert.False(t, f.IsJSON())
assert.False(t, f.IsSidecar())
}
})
t.Run("iphone_7.json", func(t *testing.T) {
if f, err := NewMediaFile(filepath.Join(c.ExamplesPath(), "iphone_7.json")); err != nil {
t.Fatal(err)
} else {
assert.False(t, f.IsLive())
assert.False(t, f.IsRaw())
assert.False(t, f.IsImage())
assert.False(t, f.IsVideo())
assert.True(t, f.IsJSON())
assert.True(t, f.IsSidecar())
}
})
}
@ -1526,77 +1580,77 @@ func TestMediaFile_IsAnimated(t *testing.T) {
if f, err := NewMediaFile("testdata/star.avifs"); err != nil {
t.Fatal(err)
} else {
assert.Equal(t, true, f.IsImage())
assert.Equal(t, true, f.IsAvifS())
assert.Equal(t, true, f.IsAnimated())
assert.Equal(t, false, f.NotAnimated())
assert.Equal(t, true, f.IsAnimatedImage())
assert.Equal(t, true, f.ExifSupported())
assert.Equal(t, false, f.IsVideo())
assert.Equal(t, false, f.IsGif())
assert.Equal(t, false, f.IsWebp())
assert.Equal(t, false, f.IsAvif())
assert.Equal(t, false, f.IsHeic())
assert.Equal(t, false, f.IsHeicS())
assert.Equal(t, false, f.IsSidecar())
assert.True(t, f.IsImage())
assert.True(t, f.IsAvifS())
assert.True(t, f.IsAnimated())
assert.False(t, f.NotAnimated())
assert.True(t, f.IsAnimatedImage())
assert.True(t, f.ExifSupported())
assert.False(t, f.IsVideo())
assert.False(t, f.IsGif())
assert.False(t, f.IsWebp())
assert.False(t, f.IsAvif())
assert.False(t, f.IsHeic())
assert.False(t, f.IsHeicS())
assert.False(t, f.IsSidecar())
}
})
t.Run("windows95.webp", func(t *testing.T) {
if f, err := NewMediaFile("testdata/windows95.webp"); err != nil {
t.Fatal(err)
} else {
assert.Equal(t, true, f.IsImage())
assert.Equal(t, true, f.IsWebp())
assert.Equal(t, true, f.IsAnimated())
assert.Equal(t, false, f.NotAnimated())
assert.Equal(t, true, f.IsAnimatedImage())
assert.Equal(t, false, f.ExifSupported())
assert.Equal(t, false, f.IsVideo())
assert.Equal(t, false, f.IsGif())
assert.Equal(t, false, f.IsAvif())
assert.Equal(t, false, f.IsAvifS())
assert.Equal(t, false, f.IsHeic())
assert.Equal(t, false, f.IsHeicS())
assert.Equal(t, false, f.IsSidecar())
assert.True(t, f.IsImage())
assert.True(t, f.IsWebp())
assert.True(t, f.IsAnimated())
assert.False(t, f.NotAnimated())
assert.True(t, f.IsAnimatedImage())
assert.False(t, f.ExifSupported())
assert.False(t, f.IsVideo())
assert.False(t, f.IsGif())
assert.False(t, f.IsAvif())
assert.False(t, f.IsAvifS())
assert.False(t, f.IsHeic())
assert.False(t, f.IsHeicS())
assert.False(t, f.IsSidecar())
}
})
t.Run("example.gif", func(t *testing.T) {
if f, err := NewMediaFile(filepath.Join(c.ExamplesPath(), "example.gif")); err != nil {
t.Fatal(err)
} else {
assert.Equal(t, true, f.IsImage())
assert.Equal(t, false, f.IsVideo())
assert.Equal(t, false, f.IsAnimated())
assert.Equal(t, true, f.NotAnimated())
assert.Equal(t, true, f.IsGif())
assert.Equal(t, false, f.IsAnimatedImage())
assert.Equal(t, false, f.IsSidecar())
assert.True(t, f.IsImage())
assert.False(t, f.IsVideo())
assert.False(t, f.IsAnimated())
assert.True(t, f.NotAnimated())
assert.True(t, f.IsGif())
assert.False(t, f.IsAnimatedImage())
assert.False(t, f.IsSidecar())
}
})
t.Run("pythagoras.gif", func(t *testing.T) {
if f, err := NewMediaFile(filepath.Join(c.ExamplesPath(), "pythagoras.gif")); err != nil {
t.Fatal(err)
} else {
assert.Equal(t, true, f.IsImage())
assert.Equal(t, false, f.IsVideo())
assert.Equal(t, true, f.IsAnimated())
assert.Equal(t, false, f.NotAnimated())
assert.Equal(t, true, f.IsGif())
assert.Equal(t, true, f.IsAnimatedImage())
assert.Equal(t, false, f.IsSidecar())
assert.True(t, f.IsImage())
assert.False(t, f.IsVideo())
assert.True(t, f.IsAnimated())
assert.False(t, f.NotAnimated())
assert.True(t, f.IsGif())
assert.True(t, f.IsAnimatedImage())
assert.False(t, f.IsSidecar())
}
})
t.Run("christmas.mp4", func(t *testing.T) {
if f, err := NewMediaFile(filepath.Join(c.ExamplesPath(), "christmas.mp4")); err != nil {
t.Fatal(err)
} else {
assert.Equal(t, false, f.IsImage())
assert.Equal(t, true, f.IsVideo())
assert.Equal(t, true, f.IsAnimated())
assert.Equal(t, false, f.NotAnimated())
assert.Equal(t, false, f.IsGif())
assert.Equal(t, false, f.IsAnimatedImage())
assert.Equal(t, false, f.IsSidecar())
assert.False(t, f.IsImage())
assert.True(t, f.IsVideo())
assert.True(t, f.IsAnimated())
assert.False(t, f.NotAnimated())
assert.False(t, f.IsGif())
assert.False(t, f.IsAnimatedImage())
assert.False(t, f.IsSidecar())
}
})
}
@ -2222,7 +2276,7 @@ func TestMediaFile_FileType(t *testing.T) {
assert.Equal(t, "png", string(m.FileType()))
assert.Equal(t, "image/jpeg", m.MimeType())
assert.Equal(t, "image/jpeg", m.BaseType())
assert.Equal(t, true, m.HasMimeType("image/jpeg"))
assert.True(t, m.HasMimeType("image/jpeg"))
assert.Equal(t, fs.ImagePng, m.FileType())
assert.Equal(t, ".png", m.Extension())
})
@ -2238,7 +2292,7 @@ func TestMediaFile_FileType(t *testing.T) {
assert.False(t, m.IsPng())
assert.Equal(t, "thm", string(m.FileType()))
assert.Equal(t, "image/jpeg", m.MimeType())
assert.Equal(t, true, m.HasMimeType("image/jpeg"))
assert.True(t, m.HasMimeType("image/jpeg"))
assert.Equal(t, fs.ImageThumb, m.FileType())
assert.Equal(t, ".thm", m.Extension())
})

View file

@ -96,8 +96,8 @@ func (t Type) FindFirst(fileName string, dirs []string, baseDir string, stripSeq
fileBaseLower := strings.ToLower(fileBasePrefix)
fileBaseUpper := strings.ToUpper(fileBasePrefix)
fileDir := filepath.Dir(fileName)
search := append([]string{fileDir}, dirs...)
filePath := filepath.Dir(fileName)
search := append([]string{filePath}, dirs...)
for _, ext := range FileTypes[t] {
lastDir := ""
@ -109,11 +109,11 @@ func (t Type) FindFirst(fileName string, dirs []string, baseDir string, stripSeq
lastDir = dir
if dir != fileDir {
if dir != filePath {
if filepath.IsAbs(dir) {
dir = filepath.Join(dir, RelName(fileDir, baseDir))
dir = filepath.Join(dir, RelName(filePath, baseDir))
} else {
dir = filepath.Join(fileDir, dir)
dir = filepath.Join(filePath, dir)
}
}
@ -145,8 +145,8 @@ func (t Type) FindAll(fileName string, dirs []string, baseDir string, stripSeque
fileBaseLower := strings.ToLower(fileBasePrefix)
fileBaseUpper := strings.ToUpper(fileBasePrefix)
fileDir := filepath.Dir(fileName)
search := append([]string{fileDir}, dirs...)
filePath := filepath.Dir(fileName)
search := append([]string{filePath}, dirs...)
for _, ext := range FileTypes[t] {
lastDir := ""
@ -158,11 +158,11 @@ func (t Type) FindAll(fileName string, dirs []string, baseDir string, stripSeque
lastDir = dir
if dir != fileDir {
if dir != filePath {
if filepath.IsAbs(dir) {
dir = filepath.Join(dir, RelName(fileDir, baseDir))
dir = filepath.Join(dir, RelName(filePath, baseDir))
} else {
dir = filepath.Join(fileDir, dir)
dir = filepath.Join(filePath, dir)
}
}

View file

@ -21,5 +21,5 @@ func FromName(fileName string) Type {
// MainFile checks if the filename belongs to a main content type.
func MainFile(fileName string) bool {
return FromName(fileName).Main()
return FromName(fileName).IsMain()
}

View file

@ -22,14 +22,9 @@ func (t Type) NotEqual(s string) bool {
return !t.Equal(s)
}
// Main checks if this is a known main media content format.
func (t Type) Main() bool {
switch t {
case Animated, Audio, Document, Image, Live, Raw, Vector, Video:
return true
default:
return false
}
// IsMain checks whether this is a primary media type, such as an image or video.
func (t Type) IsMain() bool {
return Priority[t] >= PriorityMain
}
// Unknown checks if the type is unknown.

View file

@ -6,18 +6,35 @@ import (
"github.com/stretchr/testify/assert"
)
func TestType_Main(t *testing.T) {
func TestType_IsMain(t *testing.T) {
t.Run("Unknown", func(t *testing.T) {
assert.False(t, Unknown.Main())
assert.False(t, Unknown.IsMain())
})
t.Run("Image", func(t *testing.T) {
assert.True(t, Image.Main())
assert.True(t, Image.IsMain())
})
t.Run("Video", func(t *testing.T) {
assert.True(t, Video.Main())
assert.True(t, Video.IsMain())
})
t.Run("Sidecar", func(t *testing.T) {
assert.False(t, Sidecar.Main())
assert.False(t, Sidecar.IsMain())
})
}
func TestType_Priority(t *testing.T) {
t.Run("Equal", func(t *testing.T) {
assert.Equal(t, Priority[Unknown], Priority["foo"])
assert.Equal(t, Priority[Image], Priority[Image])
assert.Equal(t, Priority[Live], Priority[Live])
assert.Equal(t, Priority[Animated], Priority[Animated])
assert.Equal(t, Priority[Animated], Priority[Audio])
assert.Equal(t, Priority[Animated], Priority[Document])
})
t.Run("Less", func(t *testing.T) {
assert.Less(t, Priority[Unknown], Priority[Image])
assert.Less(t, Priority[Unknown], Priority[Live])
assert.Less(t, Priority[Image], Priority[Live])
assert.Less(t, Priority[Video], Priority[Live])
})
}

View file

@ -1,15 +1,38 @@
package media
// Constants representing standard media types.
const (
Unknown Type = ""
Archive Type = "archive"
Sidecar Type = "sidecar"
Image Type = "image"
Video Type = "video"
Animated Type = "animated"
Audio Type = "audio"
Document Type = "document"
Image Type = "image"
Raw Type = "raw"
Sidecar Type = "sidecar"
Live Type = "live"
Vector Type = "vector"
Video Type = "video"
Live Type = "live"
)
// PriorityMain specifies the minimum priority for main media types,
// like Animated, Audio, Document, Image, Live, Raw, Vector, and Video.
const PriorityMain = 4
// Priorities maps media types to integer values that represent their relative importance.
type Priorities map[Type]int
// Priority assigns a relative priority value to the media type constants defined above.
var Priority = Priorities{
Unknown: 0,
Sidecar: 1,
Archive: 2,
Image: PriorityMain,
Video: 8,
Animated: 16,
Audio: 16,
Document: 16,
Raw: 32,
Vector: 32,
Live: 64,
}