fix(parser): handle collab lockup metadata rows

This commit is contained in:
Nesrine Gharbi 2026-09-19 18:46:10 +00:00
parent c88230067b
commit 636e64ed3e
2 changed files with 105 additions and 1 deletions

View File

@ -0,0 +1,99 @@
require "../../parsers_helper.cr"
Spectator.describe "LockupViewModelParser channel videos" do
def lockup_video(metadata_rows : Array(JSON::Any)) : JSON::Any
JSON.parse({
"lockupViewModel" => {
"contentType" => "LOCKUP_CONTENT_TYPE_VIDEO",
"contentId" => "video123",
"contentImage" => {
"thumbnailViewModel" => {
"image" => {
"sources" => [{"url" => "https://example.invalid/thumb.jpg"}],
},
"overlays" => [{
"thumbnailBottomOverlayViewModel" => {
"badges" => [{
"thumbnailBadgeViewModel" => {"text" => "12:34"},
}],
},
}],
},
},
"metadata" => {
"lockupMetadataViewModel" => {
"title" => {"content" => "Collaboration video"},
"metadata" => {
"contentMetadataViewModel" => {
"metadataRows" => metadata_rows.map(&.raw),
},
},
},
},
},
}.to_json)
end
it "parses a normal first-row metadata layout" do
rows = [
JSON.parse({
"metadataParts" => [
{"text" => {"content" => "1.5M views"}},
{"text" => {"content" => "3 days ago"}},
],
}.to_json),
]
result = parse_item(lockup_video(rows), "Example", "UC123")
expect(result).to be_a(SearchVideo)
video = result.as(SearchVideo)
expect(video.views).to eq(1_500_000)
expect(video.published).to be_close(Time.utc - 3.days, 2.seconds)
expect(video.length_seconds).to eq(754)
end
it "parses metadata after a collaboration author row" do
rows = [
JSON.parse({
"metadataParts" => [
{"text" => {"content" => "Example and Collaborator"}},
],
}.to_json),
JSON.parse({
"metadataParts" => [
{"text" => {"content" => "1.5M views"}},
{"text" => {"content" => "3 days ago"}},
],
}.to_json),
]
result = parse_item(lockup_video(rows), "Example", "UC123")
expect(result).to be_a(SearchVideo)
video = result.as(SearchVideo)
expect(video.views).to eq(1_500_000)
expect(video.published).to be_close(Time.utc - 3.days, 2.seconds)
expect(video.author).to eq("Example")
expect(video.ucid).to eq("UC123")
end
it "skips metadata rows that do not contain metadataParts" do
rows = [
JSON.parse("{}"),
JSON.parse({
"metadataParts" => [
{"text" => {"content" => "1.5M views"}},
{"text" => {"content" => "3 days ago"}},
],
}.to_json),
]
result = parse_item(lockup_video(rows), "Example", "UC123")
expect(result).to be_a(SearchVideo)
video = result.as(SearchVideo)
expect(video.views).to eq(1_500_000)
expect(video.published).to be_close(Time.utc - 3.days, 2.seconds)
end
end

View File

@ -662,7 +662,12 @@ private module Parsers
metadata = item_contents.dig("metadata", "lockupMetadataViewModel")
title = metadata.dig("title", "content").as_s
# Contains the views of the video and the published time of the video.
metadata_parts = metadata.dig("metadata", "contentMetadataViewModel", "metadataRows", 0, "metadataParts").try &.as_a
# Collaboration videos can prepend author rows before the actual video metadata,
# so collect metadata parts from every row and skip rows without metadataParts.
metadata_rows = metadata.dig?("metadata", "contentMetadataViewModel", "metadataRows").try &.as_a
metadata_parts = metadata_rows.try &.compact_map { |row|
row["metadataParts"]?.try &.as_a
}.try &.flatten
view_count_text = metadata_parts.try &.find { |item| item["icon"]?.nil? && item.dig?("text", "content").try &.as_s.includes?("views") }
.try &.dig("text", "content").as_s