mirror of
https://github.com/iv-org/invidious.git
synced 2026-01-28 07:48:31 -06:00
184 lines
5.9 KiB
Crystal
184 lines
5.9 KiB
Crystal
require "http"
|
|
require "yaml"
|
|
require "digest/sha1"
|
|
require "option_parser"
|
|
require "colorize"
|
|
|
|
# Script to fetch SABR (Server ABR) dependencies
|
|
# These are pre-built bundles for client-side SABR streaming support
|
|
|
|
SABR_DEPENDENCIES = {
|
|
"shaka-player" => {
|
|
"version" => "4.16.4",
|
|
"files" => [
|
|
{"url" => "https://cdn.jsdelivr.net/npm/shaka-player@4.16.4/dist/shaka-player.ui.js", "dest" => "shaka-player.ui.js"},
|
|
{"url" => "https://cdn.jsdelivr.net/npm/shaka-player@4.16.4/dist/controls.css", "dest" => "controls.css"},
|
|
]
|
|
},
|
|
"googlevideo" => {
|
|
"version" => "4.0.4",
|
|
"files" => [
|
|
# esm.sh bundled version - fetch full bundle path directly
|
|
{"url" => "https://esm.sh/googlevideo@4.0.4/es2022/sabr-streaming-adapter.bundle.mjs", "dest" => "googlevideo.bundle.min.js"},
|
|
]
|
|
},
|
|
"youtubei.js" => {
|
|
"version" => "16.0.1",
|
|
"files" => [
|
|
# Use the web bundle from jsdelivr (pre-built by youtubei.js)
|
|
{"url" => "https://cdn.jsdelivr.net/npm/youtubei.js@16.0.1/bundle/browser.min.js", "dest" => "youtubei.bundle.min.js"},
|
|
]
|
|
},
|
|
"bgutils-js" => {
|
|
"version" => "3.2.0",
|
|
"files" => [
|
|
{"url" => "https://esm.sh/bgutils-js@3.2.0/es2022/bgutils-js.bundle.mjs", "dest" => "bgutils.bundle.min.js"},
|
|
]
|
|
},
|
|
}
|
|
|
|
def update_versions_yaml(dep_name : String, version : String)
|
|
File.open("assets/js/sabr/#{dep_name}/versions.yml", "w") do |io|
|
|
YAML.build(io) do |builder|
|
|
builder.mapping do
|
|
builder.scalar "version"
|
|
builder.scalar version
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
# Create the main sabr directory if it doesn't exist
|
|
sabr_dir = "assets/js/sabr"
|
|
Dir.mkdir_p(sabr_dir) unless Dir.exists?(sabr_dir)
|
|
|
|
dependencies_to_install = [] of String
|
|
|
|
SABR_DEPENDENCIES.each do |dep_name, dep_info|
|
|
path = "#{sabr_dir}/#{dep_name}"
|
|
version = dep_info["version"].as(String)
|
|
|
|
if !Dir.exists?(path)
|
|
Dir.mkdir_p(path)
|
|
dependencies_to_install << dep_name
|
|
else
|
|
if File.exists?("#{path}/versions.yml")
|
|
config = File.open("#{path}/versions.yml") do |file|
|
|
YAML.parse(file).as_h
|
|
end
|
|
|
|
if config["version"].as_s != version
|
|
# Clean old files
|
|
Dir.glob("#{path}/*.js").each { |f| File.delete(f) }
|
|
Dir.glob("#{path}/*.css").each { |f| File.delete(f) }
|
|
dependencies_to_install << dep_name
|
|
end
|
|
else
|
|
dependencies_to_install << dep_name
|
|
end
|
|
end
|
|
end
|
|
|
|
channel = Channel(String | Exception).new
|
|
|
|
dependencies_to_install.each do |dep_name|
|
|
spawn do
|
|
dep_info = SABR_DEPENDENCIES[dep_name]
|
|
version = dep_info["version"].as(String)
|
|
files = dep_info["files"].as(Array(Hash(String, String)))
|
|
dest_path = "#{sabr_dir}/#{dep_name}"
|
|
|
|
files.each do |file_info|
|
|
url = file_info["url"]
|
|
dest_file = file_info["dest"]
|
|
|
|
HTTP::Client.get(url) do |response|
|
|
if response.status_code == 200
|
|
File.write("#{dest_path}/#{dest_file}", response.body_io.gets_to_end)
|
|
else
|
|
raise Exception.new("Failed to fetch #{url}: HTTP #{response.status_code}")
|
|
end
|
|
end
|
|
end
|
|
|
|
update_versions_yaml(dep_name, version)
|
|
channel.send(dep_name)
|
|
rescue ex
|
|
channel.send(ex)
|
|
end
|
|
end
|
|
|
|
if dependencies_to_install.empty?
|
|
puts "#{"SABR".colorize(:blue)} #{"dependencies".colorize(:green)} are satisfied"
|
|
else
|
|
puts "#{"Resolving".colorize(:green)} #{"SABR".colorize(:blue)} dependencies"
|
|
dependencies_to_install.size.times do
|
|
result = channel.receive
|
|
|
|
if result.is_a? Exception
|
|
raise result
|
|
end
|
|
|
|
puts "#{"Fetched".colorize(:green)} #{result.colorize(:blue)}"
|
|
end
|
|
end
|
|
|
|
# Post-process: Remove Google Fonts from Shaka controls.css
|
|
shaka_css_path = "#{sabr_dir}/shaka-player/controls.css"
|
|
if File.exists?(shaka_css_path)
|
|
css_content = File.read(shaka_css_path)
|
|
# Remove @font-face rule that loads from fonts.gstatic.com
|
|
css_content = css_content.gsub(/@font-face\{[^}]*fonts\.gstatic\.com[^}]*\}/, "")
|
|
# Replace Roboto font-family with system fonts
|
|
css_content = css_content.gsub(/font-family:\s*Roboto[^;]*;/, "font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;")
|
|
File.write(shaka_css_path, css_content)
|
|
puts "#{"Patched".colorize(:green)} Shaka CSS to use system fonts"
|
|
end
|
|
|
|
# Post-process: Patch googlevideo bundle to remove esm.sh import and add process shim
|
|
googlevideo_path = "#{sabr_dir}/googlevideo/googlevideo.bundle.min.js"
|
|
if File.exists?(googlevideo_path)
|
|
js_content = File.read(googlevideo_path)
|
|
|
|
# Add process shim at the beginning and remove the esm.sh import
|
|
process_shim = <<-JS
|
|
// Browser-compatible process shim for googlevideo
|
|
var __Process$ = { env: {} };
|
|
|
|
JS
|
|
|
|
# Remove the esm.sh import line: import __Process$ from "/node/process.mjs";
|
|
js_content = js_content.gsub(/import\s+__Process\$\s+from\s*["'][^"']+["'];?\s*/, "")
|
|
|
|
# Prepend the shim
|
|
js_content = process_shim + js_content
|
|
|
|
File.write(googlevideo_path, js_content)
|
|
puts "#{"Patched".colorize(:green)} googlevideo bundle with process shim"
|
|
end
|
|
|
|
# Post-process: Patch bgutils-js bundle to be self-contained
|
|
bgutils_path = "#{sabr_dir}/bgutils-js/bgutils.bundle.min.js"
|
|
if File.exists?(bgutils_path)
|
|
js_content = File.read(bgutils_path)
|
|
|
|
# Check if it's just an export redirect and fetch the actual bundle
|
|
if js_content.includes?("export * from")
|
|
# The esm.sh bundle is just a redirect, we need the actual content
|
|
puts "#{"Info".colorize(:yellow)} bgutils bundle is a redirect, fetching actual content..."
|
|
|
|
# Extract the actual path from: export * from "/bgutils-js@3.1.3/es2022/bgutils-js.bundle.mjs";
|
|
if match = js_content.match(/export \* from ["']([^"']+)["']/)
|
|
actual_path = match[1]
|
|
actual_url = "https://esm.sh#{actual_path}"
|
|
|
|
HTTP::Client.get(actual_url) do |response|
|
|
if response.status_code == 200
|
|
File.write(bgutils_path, response.body_io.gets_to_end)
|
|
puts "#{"Fetched".colorize(:green)} actual bgutils bundle"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|