Skip to content

feat(search): video facet - #3201

Draft
dschmidt wants to merge 1 commit into
feat/search-tika-facetsfrom
feat/search-video-facet
Draft

feat(search): video facet#3201
dschmidt wants to merge 1 commit into
feat/search-tika-facetsfrom
feat/search-video-facet

Conversation

@dschmidt

@dschmidt dschmidt commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Stacked on #3198 (tika facets).

Draft: adds the video facet (dimensions, duration, codec, audio stream details) to the search index, the search API and the graph driveItem.

Maps what Apache Tika exposes for MP4/MOV today: width, height, duration, fourCC (video codec), audioSamplesPerSecond, audioChannels. Verified against the pinned Tika 4.0 snapshot with a real testVideoMp4.mp4.

Tika stores the video track dimensions under the same tiff:ImageWidth/tiff:ImageLength keys it uses for images (via Metadata.IMAGE_WIDTH), so image and video would otherwise both match. getImage is now gated on the image/ content type and getVideo on video/, inside the respective facet function, so a file gets exactly one of the two.

Still missing in Tika (left as TODOs in tika_video.go and the test):

  • bitrate — Tika exposes no video bitrate; would need computing (media size / duration).
  • frameRate — metadata-extractor's Mp4VideoDirectory has no frame-rate tag; would need computing from the sample-timing table.
  • audioBitsPerSampleMp4SoundDirectory.TAG_AUDIO_SAMPLE_SIZE exists but MP4Parser doesn't map it (easy to add upstream, like the audio:* keys).
  • audioFormatMP4Parser only sets xmpDM:audioCompressor for audio-typed files (and to the container major brand, not the codec), so it never fires for a video/* file. Needs tika to expose the audio track's codec.
  • nice-to-have: a numeric audio channel count. Tika only emits the Mono/Stereo enum and drops >2 channels, so we map it heuristically; a raw count from Tika would be cleaner.

Needs a separate reva change, not includable here (same as the motion-photo PR): the WebDAV PROPFIND handler must know the video keys to expose the facet over WebDAV. It lives in vendored reva, so it needs its own reva PR + dependency bump. The required diff:

diff --git a/vendor/github.com/opencloud-eu/reva/v2/internal/http/services/owncloud/ocdav/propfind/propfind.go b/vendor/github.com/opencloud-eu/reva/v2/internal/http/services/owncloud/ocdav/propfind/propfind.go
index d86367a2c5..8e4af07848 100644
--- a/vendor/github.com/opencloud-eu/reva/v2/internal/http/services/owncloud/ocdav/propfind/propfind.go
+++ b/vendor/github.com/opencloud-eu/reva/v2/internal/http/services/owncloud/ocdav/propfind/propfind.go
@@ -107,6 +107,18 @@ var (
 		"orientation",
 		"takenDateTime",
 	}
+	videoKeys = []string{
+		"audioBitsPerSample",
+		"audioChannels",
+		"audioFormat",
+		"audioSamplesPerSecond",
+		"bitrate",
+		"duration",
+		"fourCC",
+		"frameRate",
+		"height",
+		"width",
+	}
 )
 
 type countingReader struct {
@@ -887,6 +899,8 @@ func metadataKeys(pf XML) ([]string, []string) {
 					metadataKeys = append(metadataKeys, metadataKeysWithPrefix("libre.graph.image", imageKeys)...)
 				case "http://owncloud.org/ns/photo":
 					metadataKeys = append(metadataKeys, metadataKeysWithPrefix("libre.graph.photo", photoKeys)...)
+				case "http://owncloud.org/ns/video":
+					metadataKeys = append(metadataKeys, metadataKeysWithPrefix("libre.graph.video", videoKeys)...)
 				default:
 					metadataKeys = append(metadataKeys, key)
 				}
@@ -944,7 +958,7 @@ func requiresExplicitFetching(n *xml.Name) bool {
 		}
 	case net.NsOwncloud:
 		switch n.Local {
-		case "favorite", "share-types", "checksums", "size", "tags", "audio", "location", "image", "photo":
+		case "favorite", "share-types", "checksums", "size", "tags", "audio", "location", "image", "photo", "video":
 			return true
 		default:
 			return false
@@ -1292,6 +1306,7 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
 			appendMetadataProp(k, "oc", "location", "libre.graph.location", locationKeys)
 			appendMetadataProp(k, "oc", "image", "libre.graph.image", imageKeys)
 			appendMetadataProp(k, "oc", "photo", "libre.graph.photo", photoKeys)
+			appendMetadataProp(k, "oc", "video", "libre.graph.video", videoKeys)
 		}
 
 		if md.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER {
@@ -1579,6 +1594,10 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
 					if k := md.GetArbitraryMetadata().GetMetadata(); k != nil {
 						appendMetadataProp(k, "oc", "photo", "libre.graph.photo", photoKeys)
 					}
+				case "video":
+					if k := md.GetArbitraryMetadata().GetMetadata(); k != nil {
+						appendMetadataProp(k, "oc", "video", "libre.graph.video", videoKeys)
+					}
 				case "name":
 					appendToOK(prop.Escaped("oc:name", md.Name))
 				case "shareid":

@codacy-production

Copy link
Copy Markdown

Not up to standards ⛔

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@dschmidt
dschmidt force-pushed the feat/search-video-facet branch from 5aa11c6 to 22f66de Compare July 30, 2026 11:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant