mirror of
https://github.com/iv-org/invidious.git
synced 2026-09-06 00:52:45 -05:00
fix(captions): match preferred language to auto-generated tracks
Preferred caption slots use names such as English, but many videos only expose English (auto-generated) with language code en. Exact name matching left those tracks unordered, so the player could auto-select another auto-generated language. Match preference names to regional and auto-generated variants, keep human tracks ahead of auto-generated ones, and share the matcher on watch and embed. Fixes #6007
This commit is contained in:
parent
049d591d29
commit
a4d0a195cd
36
spec/invidious/videos/captions_matching_spec.cr
Normal file
36
spec/invidious/videos/captions_matching_spec.cr
Normal file
@ -0,0 +1,36 @@
|
||||
require "../../spec_helper"
|
||||
|
||||
Spectator.describe Invidious::Videos::Captions do
|
||||
describe ".matching" do
|
||||
it "matches English to English auto-generated ahead of other auto tracks" do
|
||||
arabic = Invidious::Videos::Captions::Metadata.new("Arabic (auto-generated)", "ar", "http://x", true)
|
||||
english_auto = Invidious::Videos::Captions::Metadata.new("English (auto-generated)", "en", "http://x", true)
|
||||
|
||||
matched = Invidious::Videos::Captions.matching([arabic, english_auto], ["English"])
|
||||
expect(matched.map(&.name)).to eq(["English (auto-generated)"])
|
||||
end
|
||||
|
||||
it "prefers a human English track over auto-generated English" do
|
||||
english_auto = Invidious::Videos::Captions::Metadata.new("English (auto-generated)", "en", "http://x", true)
|
||||
english = Invidious::Videos::Captions::Metadata.new("English", "en", "http://x", false)
|
||||
|
||||
matched = Invidious::Videos::Captions.matching([english_auto, english], ["English"])
|
||||
expect(matched.map(&.name)).to eq(["English", "English (auto-generated)"])
|
||||
end
|
||||
|
||||
it "matches regional English names and language codes" do
|
||||
us = Invidious::Videos::Captions::Metadata.new("English (United States)", "en-US", "http://x", false)
|
||||
uk = Invidious::Videos::Captions::Metadata.new("English (United Kingdom)", "en-GB", "http://x", false)
|
||||
german = Invidious::Videos::Captions::Metadata.new("German (Germany)", "de-DE", "http://x", false)
|
||||
|
||||
matched = Invidious::Videos::Captions.matching([german, us, uk], ["English", "en"])
|
||||
expect(matched.map(&.name)).to eq(["English (United States)", "English (United Kingdom)"])
|
||||
end
|
||||
|
||||
it "ignores blank preference slots" do
|
||||
arabic = Invidious::Videos::Captions::Metadata.new("Arabic (auto-generated)", "ar", "http://x", true)
|
||||
matched = Invidious::Videos::Captions.matching([arabic], ["", "", ""])
|
||||
expect(matched).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -182,14 +182,7 @@ module Invidious::Routes::Embed
|
||||
|
||||
captions = video.captions
|
||||
|
||||
preferred_captions = captions.select { |caption|
|
||||
params.preferred_captions.includes?(caption.name) ||
|
||||
params.preferred_captions.includes?(caption.language_code.split("-")[0])
|
||||
}
|
||||
preferred_captions.sort_by! { |caption|
|
||||
(params.preferred_captions.index(caption.name) ||
|
||||
params.preferred_captions.index(caption.language_code.split("-")[0])).not_nil!
|
||||
}
|
||||
preferred_captions = Invidious::Videos::Captions.matching(captions, params.preferred_captions)
|
||||
captions = captions - preferred_captions
|
||||
|
||||
aspect_ratio = nil
|
||||
|
||||
@ -149,14 +149,7 @@ module Invidious::Routes::Watch
|
||||
|
||||
captions = video.captions
|
||||
|
||||
preferred_captions = captions.select { |caption|
|
||||
params.preferred_captions.includes?(caption.name) ||
|
||||
params.preferred_captions.includes?(caption.language_code.split("-")[0])
|
||||
}
|
||||
preferred_captions.sort_by! { |caption|
|
||||
(params.preferred_captions.index(caption.name) ||
|
||||
params.preferred_captions.index(caption.language_code.split("-")[0])).not_nil!
|
||||
}
|
||||
preferred_captions = Invidious::Videos::Captions.matching(captions, params.preferred_captions)
|
||||
captions = captions - preferred_captions
|
||||
|
||||
aspect_ratio = "16:9"
|
||||
|
||||
@ -86,6 +86,49 @@ module Invidious::Videos
|
||||
end
|
||||
end
|
||||
|
||||
# Tracks whose name or language matches the user's caption preferences,
|
||||
# ranked by preference slot then human tracks before auto-generated.
|
||||
def self.matching(captions : Array(Metadata), names : Array(String)) : Array(Metadata)
|
||||
wanted = names.map(&.strip).reject(&.empty?)
|
||||
return [] of Metadata if wanted.empty?
|
||||
|
||||
selected = captions.select { |caption| matches?(caption, wanted) }
|
||||
selected.sort_by! { |caption| rank(caption, wanted) }
|
||||
selected
|
||||
end
|
||||
|
||||
def self.matches?(caption : Metadata, names : Array(String)) : Bool
|
||||
names.any? { |name| name_matches?(caption, name) }
|
||||
end
|
||||
|
||||
private def self.name_matches?(caption : Metadata, name : String) : Bool
|
||||
needle = name.strip.downcase
|
||||
return false if needle.empty?
|
||||
|
||||
caption_name = caption.name.downcase
|
||||
lang = caption.language_code.downcase
|
||||
base_lang = lang.split("-")[0]
|
||||
|
||||
caption_name == needle ||
|
||||
caption_name.starts_with?(needle + " (") ||
|
||||
caption_name.starts_with?(needle + " - ") ||
|
||||
lang == needle ||
|
||||
base_lang == needle
|
||||
end
|
||||
|
||||
private def self.rank(caption : Metadata, names : Array(String)) : Tuple(Int32, Int32)
|
||||
pref_rank = names.size
|
||||
names.each_with_index do |name, index|
|
||||
if name_matches?(caption, name)
|
||||
pref_rank = index
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
auto_rank = caption.auto_generated ? 1 : 0
|
||||
{pref_rank, auto_rank}
|
||||
end
|
||||
|
||||
# List of all caption languages available on Youtube.
|
||||
LANGUAGES = {
|
||||
"",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user