summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorsyeopite <syeopite@syeopite.dev>2021-09-11 22:18:45 -0700
committersyeopite <syeopite@syeopite.dev>2021-09-18 13:30:15 -0700
commit262131f68e74d3de804b7804a7934ec8f237e75d (patch)
tree58e92ed37ade57fa4a655b71f47e436c7e4bd4d3 /scripts
parentceae48088e9a634975c7e47c4a532e7e64d6773e (diff)
downloadinvidious-262131f68e74d3de804b7804a7934ec8f237e75d.tar.gz
invidious-262131f68e74d3de804b7804a7934ec8f237e75d.tar.bz2
invidious-262131f68e74d3de804b7804a7934ec8f237e75d.zip
Add script to resolve and fetch VideoJS files
Diffstat (limited to 'scripts')
-rw-r--r--scripts/fetch-videojs-dependencies.cr153
1 files changed, 153 insertions, 0 deletions
diff --git a/scripts/fetch-videojs-dependencies.cr b/scripts/fetch-videojs-dependencies.cr
new file mode 100644
index 00000000..cd94b214
--- /dev/null
+++ b/scripts/fetch-videojs-dependencies.cr
@@ -0,0 +1,153 @@
+require "http"
+require "yaml"
+require "digest/sha1"
+require "option_parser"
+require "colorize"
+
+# Taken from https://crystal-lang.org/api/1.1.1/OptionParser.html
+minified = false
+OptionParser.parse do |parser|
+ parser.banner = "Usage: Fetch VideoJS dependencies [arguments]"
+ parser.on("-m", "--minified", "Use minified versions of VideoJS dependencies (performance and bandwidth benefit)") { minified = true }
+
+ parser.on("-h", "--help", "Show this help") do
+ puts parser
+ exit
+ end
+
+ parser.invalid_option do |flag|
+ STDERR.puts "ERROR: #{flag} is not a valid option."
+ STDERR.puts parser
+ exit(1)
+ end
+end
+
+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
+# different or the requested dependency just isn't present, then it needs to be
+# installed.
+
+# Since we can't know when videojs-youtube-annotations is updated, we'll just always fetch
+# a new copy each time.
+dependencies_to_install = [] of String
+
+required_dependencies.keys.each do |dep|
+ dep = dep.to_s
+ path = "assets/videojs/#{dep}"
+ # Check for missing dependencies
+ if !Dir.exists?(path)
+ Dir.mkdir(path)
+
+ update_versions_yaml(required_dependencies, minified, dep)
+ dependencies_to_install << dep
+ else
+ config = File.open("#{path}/versions.yml") do |file|
+ YAML.parse(file).as_h
+ end
+
+ if config["version"].as_s != required_dependencies[dep]["version"].as_s || config["minified"].as_bool != minified
+ `rm -rf #{path}/*`
+ dependencies_to_install << dep
+ update_versions_yaml(required_dependencies, minified, dep)
+ end
+ end
+end
+
+# Now we begin the fun part of installing the dependencies.
+# 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).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)
+
+ if Digest::SHA1.hexdigest(data) != 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.
+ args = Process.parse_arguments("-zxvf '#{download_path}/package.tgz' -C '#{download_path}'")
+ process = Process.new("tar", args: args)
+ process.wait.success? # => true
+
+ # 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/#{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?("#{tmp_dir_path}/#{dep}/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
+
+ channel.send(dep_name)
+ end
+end
+
+puts "#{"Resolving".colorize(:green)} #{"VideoJS".colorize(:blue)} dependencies"
+dependencies_to_install.size.times do
+ result = channel.receive
+ puts "#{"Fetched".colorize(:green)} #{result.colorize(:blue)}"
+end
+
+# Cleanup
+`rm -rf #{tmp_dir_path}`