fix(search): read the tika 4 live photo keys

Tika 4 prefixes its metadata keys (mp4:, img:), so the live photo facet was never built there. Live photo support needs tika 4: tika 3 got the video keys only in 3.3.2 and never the still image time. The content key is read through one lookup, marked tika 4 and tika 3 legacy.
This commit is contained in:
Dominik Schmidt committed 2026-10-03 11:12:17 +02:00
1 parent a3255422b8
commit 4006344505
3 files changed
+25 -26

No files matched your search

+4 -4
View File
@@ -95,10 +95,10 @@ func (t Tika) Extract(ctx context.Context, ri *provider.ResourceInfo) (Document,
doc.Title = strings.TrimSpace(fmt.Sprintf("%s %s", doc.Title, title))
}
// tika 4 renamed the meta prefix from X-TIKA: to tk:
if content, err := getFirstValue(meta, "tk:content"); err == nil {
doc.Content = strings.TrimSpace(fmt.Sprintf("%s %s", doc.Content, content))
} else if content, err := getFirstValue(meta, "X-TIKA:content"); err == nil {
if content, err := getFirstValue(meta,
"tk:content", // tika 4
"X-TIKA:content", // tika 3 legacy
); err == nil {
doc.Content = strings.TrimSpace(fmt.Sprintf("%s %s", doc.Content, content))
}
}
@@ -10,9 +10,8 @@ import (
func (t Tika) getLivePhoto(meta map[string][]string) *libregraph.LivePhoto {
// ContentId pairs the two halves, without it there is no live photo. The
// video carries it in the QuickTime item list, the still image in the Apple
// maker note, which tika surfaces as "Content Identifier". A file is only
// ever one half, so both keys are read.
contentID, err := getFirstValue(meta, "com.apple.quicktime.content.identifier", "Content Identifier")
// maker note. A file is only ever one half, so both keys are read.
contentID, err := getFirstValue(meta, "mp4:com.apple.quicktime.content.identifier", "img:Content Identifier")
if err != nil || contentID == "" {
return nil
}
@@ -25,19 +24,19 @@ func (t Tika) getLivePhoto(meta map[string][]string) *libregraph.LivePhoto {
}
}
if v, err := getFirstValue(meta, "com.apple.quicktime.live-photo.auto"); err == nil {
if v, err := getFirstValue(meta, "mp4:com.apple.quicktime.live-photo.auto"); err == nil {
if b, err := strconv.ParseBool(v); err == nil {
livePhoto.SetAuto(b)
}
}
if v, err := getFirstValue(meta, "com.apple.quicktime.live-photo.vitality-score"); err == nil {
if v, err := getFirstValue(meta, "mp4:com.apple.quicktime.live-photo.vitality-score"); err == nil {
if f, err := strconv.ParseFloat(v, 64); err == nil {
livePhoto.SetVitalityScore(f)
}
}
if v, err := getFirstValue(meta, "com.apple.quicktime.live-photo.vitality-scoring-version"); err == nil {
if v, err := getFirstValue(meta, "mp4:com.apple.quicktime.live-photo.vitality-scoring-version"); err == nil {
if i, err := strconv.ParseInt(v, 10, 64); err == nil {
livePhoto.SetVitalityScoringVersion(i)
}
@@ -9,12 +9,12 @@ import (
var _ = Describe("getLivePhoto", func() {
It("maps the video half of a live photo", func() {
livePhoto := Tika{}.getLivePhoto(map[string][]string{
"Content-Type": {"video/quicktime"},
"com.apple.quicktime.content.identifier": {"6F1A2B3C-1234-4E5F-9A8B-0011223344CC"},
"quicktime:still-image-time": {"1500000"},
"com.apple.quicktime.live-photo.auto": {"1"},
"com.apple.quicktime.live-photo.vitality-score": {"0.75"},
"com.apple.quicktime.live-photo.vitality-scoring-version": {"4"},
"Content-Type": {"video/quicktime"},
"mp4:com.apple.quicktime.content.identifier": {"6F1A2B3C-1234-4E5F-9A8B-0011223344CC"},
"quicktime:still-image-time": {"1500000"},
"mp4:com.apple.quicktime.live-photo.auto": {"1"},
"mp4:com.apple.quicktime.live-photo.vitality-score": {"0.75"},
"mp4:com.apple.quicktime.live-photo.vitality-scoring-version": {"4"},
})
Expect(livePhoto).ToNot(BeNil())
@@ -27,8 +27,8 @@ var _ = Describe("getLivePhoto", func() {
It("maps the still half via the Apple maker-note content identifier", func() {
livePhoto := Tika{}.getLivePhoto(map[string][]string{
"Content-Type": {"image/heic"},
"Content Identifier": {"6F1A2B3C-1234-4E5F-9A8B-0011223344CC"},
"Content-Type": {"image/heic"},
"img:Content Identifier": {"6F1A2B3C-1234-4E5F-9A8B-0011223344CC"},
})
Expect(livePhoto).ToNot(BeNil())
Expect(livePhoto.ContentId).To(Equal("6F1A2B3C-1234-4E5F-9A8B-0011223344CC"))
@@ -39,15 +39,15 @@ var _ = Describe("getLivePhoto", func() {
"Content-Type": {"image/jpeg"},
})).To(BeNil())
Expect(Tika{}.getLivePhoto(map[string][]string{
"Content-Type": {"image/heic"},
"Content Identifier": {""},
"Content-Type": {"image/heic"},
"img:Content Identifier": {""},
})).To(BeNil(), "an empty pairing id is no live photo")
})
It("rounds a fractional still-image-time", func() {
livePhoto := Tika{}.getLivePhoto(map[string][]string{
"com.apple.quicktime.content.identifier": {"6F1A2B3C"},
"quicktime:still-image-time": {"1500000.7"},
"mp4:com.apple.quicktime.content.identifier": {"6F1A2B3C"},
"quicktime:still-image-time": {"1500000.7"},
})
Expect(livePhoto).ToNot(BeNil())
Expect(livePhoto.StillImageTimeUs).To(Equal(libregraph.PtrInt64(1500001)))
@@ -55,9 +55,9 @@ var _ = Describe("getLivePhoto", func() {
It("keeps the facet when optional values are malformed", func() {
livePhoto := Tika{}.getLivePhoto(map[string][]string{
"com.apple.quicktime.content.identifier": {"6F1A2B3C"},
"com.apple.quicktime.live-photo.auto": {"maybe"},
"com.apple.quicktime.live-photo.vitality-score": {"very"},
"mp4:com.apple.quicktime.content.identifier": {"6F1A2B3C"},
"mp4:com.apple.quicktime.live-photo.auto": {"maybe"},
"mp4:com.apple.quicktime.live-photo.vitality-score": {"very"},
})
Expect(livePhoto).ToNot(BeNil())
Expect(livePhoto.Auto).To(BeNil())
@@ -66,7 +66,7 @@ var _ = Describe("getLivePhoto", func() {
It("leaves the video-only fields empty on the still half", func() {
livePhoto := Tika{}.getLivePhoto(map[string][]string{
"Content Identifier": {"6F1A2B3C"},
"img:Content Identifier": {"6F1A2B3C"},
})
Expect(livePhoto).ToNot(BeNil())
Expect(livePhoto.StillImageTimeUs).To(BeNil())