Rewrite fetch logic for player dependencies

- Refactor into dedicated class
- Simplify workarounds for dependencies with differing structure
This commit is contained in:
syeopite 2024-02-18 16:49:21 -08:00
parent 9c0cb2a513
commit 3195fd06f2
No known key found for this signature in database
GPG Key ID: A73C186DA3955A1A
3 changed files with 128 additions and 82 deletions

View File

@ -4,6 +4,110 @@ require "digest/sha1"
require "option_parser"
require "colorize"
class Dependency
@dependency_config : Hash(YAML::Any, YAML::Any)
def initialize(
required_dependencies : Hash(YAML::Any, YAML::Any),
@dependency : String,
@tmp_dir_path : String,
@minified : Bool,
@skip_checksum : Bool
)
@dependency_config = required_dependencies[@dependency].as_h
@download_path = "#{@tmp_dir_path}/#{@dependency}"
@destination_path = "assets/videojs/#{@dependency}"
end
private def request
HTTP::Client.get("https://registry.npmjs.org/#{@dependency}/-/#{@dependency}-#{@dependency_config["version"]}.tgz") do |response|
Dir.mkdir(@download_path)
data = response.body_io.gets_to_end
File.write("#{@download_path}/package.tgz", data)
# https://github.com/iv-org/invidious/pull/2397#issuecomment-922375908
if !@skip_checksum && `sha1sum #{@download_path}/package.tgz`.split(" ")[0] != @dependency_config["shasum"]
raise Exception.new("Checksum for '#{@dependency}' failed")
end
end
end
private def move_file(full_target_path, extension)
minified_target_path = sprintf(full_target_path, {"file_extension": ".min.#{extension}"})
if @minified && File.exists?(minified_target_path)
target_path = minified_target_path
else
target_path = sprintf(full_target_path, {"file_extension": ".#{extension}"})
end
if download_as = @dependency_config.dig?(YAML::Any.new("install_instructions"), YAML::Any.new("download_as"))
destination_path = "#{@destination_path}/#{sprintf(download_as.as_s, {"file_extension": ".#{extension}"})}"
else
destination_path = @destination_path
end
# https://github.com/crystal-lang/crystal/issues/7777
`mv #{target_path} #{destination_path}`
end
private def fetch_path(is_css)
if is_css
instruction_path = "css_path"
else
instruction_path = "js_path"
end
# https://github.com/crystal-lang/crystal/issues/14305
if raw_target_path = @dependency_config.dig?(YAML::Any.new("install_instructions"), YAML::Any.new(instruction_path))
return "#{@download_path}/package/#{raw_target_path}"
else
return "#{@download_path}/package/dist/#{@dependency}%{file_extension}"
end
end
private def move_js_file
return self.move_file(self.fetch_path(is_css: false), "js")
end
private def move_css_file
path = self.fetch_path(is_css: true)
if File.exists?(sprintf(path, {"file_extension": ".css"}))
return move_file(path, "css")
end
end
private def update_versions_yaml
File.open("#{@destination_path}/versions.yml", "w") do |io|
YAML.build(io) do |builder|
builder.mapping do
# Versions
builder.scalar "version"
builder.scalar "#{@dependency_config["version"]}"
builder.scalar "minified"
builder.scalar @minified
end
end
end
end
def fetch
self.request
# Crystal's stdlib provides no way of extracting a tarball
`tar -vzxf '#{@download_path}/package.tgz' -C '#{@download_path}'`
raise "Extraction for #{@dependency} failed" if !$?.success?
self.move_js_file
self.move_css_file
self.update_versions_yaml
end
end
# Hacky solution to get separated arguments when called from invidious.cr
if ARGV.size == 1
parser_args = [] of String
@ -37,21 +141,6 @@ required_dependencies = File.open("videojs-dependencies.yml") do |file|
YAML.parse(file).as_h
end
def update_versions_yaml(required_dependencies, minified, dep_name)
File.open("assets/videojs/#{dep_name}/versions.yml", "w") do |io|
YAML.build(io) do |builder|
builder.mapping do
# Versions
builder.scalar "version"
builder.scalar "#{required_dependencies[dep_name]["version"]}"
builder.scalar "minified"
builder.scalar minified
end
end
end
end
# The first step is to check which dependencies we'll need to install.
# If the version we have requested in `videojs-dependencies.yml` is the
# same as what we've installed, we shouldn't do anything. Likewise, if it's
@ -103,72 +192,13 @@ end
# But first we'll setup a temp directory to store the plugins
tmp_dir_path = "#{Dir.tempdir}/invidious-videojs-dep-install"
Dir.mkdir(tmp_dir_path) if !Dir.exists? tmp_dir_path
channel = Channel(String | Exception).new
dependencies_to_install.each do |dep|
spawn do
dep_name = dep
download_path = "#{tmp_dir_path}/#{dep}"
dest_path = "assets/videojs/#{dep}"
HTTP::Client.get("https://registry.npmjs.org/#{dep}/-/#{dep}-#{required_dependencies[dep]["version"]}.tgz") do |response|
Dir.mkdir(download_path)
data = response.body_io.gets_to_end
File.write("#{download_path}/package.tgz", data)
# https://github.com/iv-org/invidious/pull/2397#issuecomment-922375908
if !skip_checksum && `sha1sum #{download_path}/package.tgz`.split(" ")[0] != required_dependencies[dep]["shasum"]
raise Exception.new("Checksum for '#{dep}' failed")
end
end
# Unless we install an external dependency, crystal provides no way of extracting a tarball.
# Thus we'll go ahead and call a system command.
`tar -vzxf '#{download_path}/package.tgz' -C '#{download_path}'`
raise "Extraction for #{dep} failed" if !$?.success?
# Would use File.rename in the following steps but for some reason it just doesn't work here.
# Video.js itself is structured slightly differently
dep = "video" if dep == "video.js"
# This dep nests everything under an additional JS or CSS folder
if dep == "silvermine-videojs-quality-selector"
js_path = "js/"
# It also stores their quality selector as `quality-selector.css`
`mv #{download_path}/package/dist/css/quality-selector.css #{dest_path}/quality-selector.css`
else
js_path = ""
end
# Would use File.rename but for some reason it just doesn't work here.
if minified && File.exists?("#{download_path}/package/dist/#{js_path}#{dep}.min.js")
`mv #{download_path}/package/dist/#{js_path}#{dep}.min.js #{dest_path}/#{dep}.js`
else
`mv #{download_path}/package/dist/#{js_path}#{dep}.js #{dest_path}/#{dep}.js`
end
# Fetch CSS which isn't guaranteed to exist
#
# Also, video JS changes structure here once again...
dep = "video-js" if dep == "video"
# VideoJS marker uses a dot on the CSS files.
dep = "videojs.markers" if dep == "videojs-markers"
if File.exists?("#{download_path}/package/dist/#{dep}.css")
if minified && File.exists?("#{download_path}/package/dist/#{dep}.min.css")
`mv #{download_path}/package/dist/#{dep}.min.css #{dest_path}/#{dep}.css`
else
`mv #{download_path}/package/dist/#{dep}.css #{dest_path}/#{dep}.css`
end
end
# Update/create versions file for the dependency
update_versions_yaml(required_dependencies, minified, dep_name)
channel.send(dep_name)
dependency = Dependency.new(required_dependencies, dep, tmp_dir_path, minified, skip_checksum)
dependency.fetch
channel.send(dep)
rescue ex
channel.send(ex)
end

View File

@ -1,12 +1,12 @@
<link rel="stylesheet" href="/videojs/video.js/video-js.css?v=<%= ASSET_COMMIT %>">
<link rel="stylesheet" href="/videojs/video.js/video.js.css?v=<%= ASSET_COMMIT %>">
<link rel="stylesheet" href="/videojs/videojs-http-source-selector/videojs-http-source-selector.css?v=<%= ASSET_COMMIT %>">
<link rel="stylesheet" href="/videojs/videojs-markers/videojs.markers.css?v=<%= ASSET_COMMIT %>">
<link rel="stylesheet" href="/videojs/videojs-markers/videojs-markers.css?v=<%= ASSET_COMMIT %>">
<link rel="stylesheet" href="/videojs/videojs-share/videojs-share.css?v=<%= ASSET_COMMIT %>">
<link rel="stylesheet" href="/videojs/videojs-vtt-thumbnails/videojs-vtt-thumbnails.css?v=<%= ASSET_COMMIT %>">
<link rel="stylesheet" href="/videojs/videojs-mobile-ui/videojs-mobile-ui.css?v=<%= ASSET_COMMIT %>">
<link rel="stylesheet" href="/css/player.css?v=<%= ASSET_COMMIT %>">
<script src="/videojs/video.js/video.js?v=<%= ASSET_COMMIT %>"></script>
<script src="/videojs/video.js/video.js.js?v=<%= ASSET_COMMIT %>"></script>
<script src="/videojs/videojs-mobile-ui/videojs-mobile-ui.js?v=<%= ASSET_COMMIT %>"></script>
<script src="/videojs/videojs-contrib-quality-levels/videojs-contrib-quality-levels.js?v=<%= ASSET_COMMIT %>"></script>
<script src="/videojs/videojs-http-source-selector/videojs-http-source-selector.js?v=<%= ASSET_COMMIT %>"></script>

View File

@ -3,6 +3,13 @@ video.js:
version: 7.12.1
shasum: 1d12eeb1f52e3679e8e4c987d9b9eb37e2247fa2
install_instructions:
js_path: "dist/video%{file_extension}"
css_path: "dist/video-js%{file_extension}"
# Normalize names to simplify File.exists? check
download_as: "video.js%{file_extension}"
videojs-contrib-quality-levels:
version: 2.1.0
shasum: 046e9e21ed01043f512b83a1916001d552457083
@ -15,6 +22,10 @@ videojs-markers:
version: 1.0.1
shasum: d7f8d804253fd587813271f8db308a22b9f7df34
install_instructions:
css_path: "dist/videojs.markers%{file_extension}"
download_as: "videojs-markers%{file_extension}"
videojs-mobile-ui:
version: 0.6.1
shasum: 0e146c4c481cbee0729cb5e162e558b455562cd0
@ -38,11 +49,16 @@ videojs-vtt-thumbnails:
# We're using iv-org's fork of videojs-quality-selector,
# which isn't published on NPM, and doesn't have any
# easy way of fetching the compiled variant.
#
# silvermine-videojs-quality-selector:
# version: 1.1.2
# shasum: 94033ff9ee52ba6da1263b97c9a74d5b3dfdf711
# install_instructions:
# js_path: "dist/js/silvermine-videojs-quality-selector%{file_extension}"
# css_path: "dist/css/quality-selector%{file_extension}"
# download_as: silvermine-videojs-quality-selector%{file_extension}
# Ditto. Although this extension contains the complied variant in its git repo,
# it lacks any sort of versioning. As such, the script will ignore it.