From 262131f68e74d3de804b7804a7934ec8f237e75d Mon Sep 17 00:00:00 2001 From: syeopite Date: Sat, 11 Sep 2021 22:18:45 -0700 Subject: [PATCH] Add script to resolve and fetch VideoJS files --- scripts/fetch-videojs-dependencies.cr | 153 ++++++++++++++++++ .../views/components/player_sources.ecr | 35 ++-- src/invidious/views/embed.ecr | 4 +- src/invidious/views/licenses.ecr | 20 +-- videojs-dependencies.yml | 45 ++++++ 5 files changed, 228 insertions(+), 29 deletions(-) create mode 100644 scripts/fetch-videojs-dependencies.cr create mode 100644 videojs-dependencies.yml 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}` diff --git a/src/invidious/views/components/player_sources.ecr b/src/invidious/views/components/player_sources.ecr index 0d97d35a..6573b542 100644 --- a/src/invidious/views/components/player_sources.ecr +++ b/src/invidious/views/components/player_sources.ecr @@ -1,18 +1,19 @@ - - - - - - + + + + + + + - - - - - - - + + + + + + + <% if params.annotations %> @@ -21,11 +22,11 @@ <% end %> <% if params.listen || params.quality != "dash" %> - - + + <% end %> <% if !params.listen && params.vr_mode %> - - + + <% end %> diff --git a/src/invidious/views/embed.ecr b/src/invidious/views/embed.ecr index dbb86009..cd0fd0d5 100644 --- a/src/invidious/views/embed.ecr +++ b/src/invidious/views/embed.ecr @@ -6,8 +6,8 @@ <%= rendered "components/player_sources" %> - - + + <%= HTML.escape(video.title) %> - Invidious diff --git a/src/invidious/views/licenses.ecr b/src/invidious/views/licenses.ecr index 9f5bcbdd..6d7f3842 100644 --- a/src/invidious/views/licenses.ecr +++ b/src/invidious/views/licenses.ecr @@ -67,7 +67,7 @@ - silvermine-videojs-quality-selector.min.js + silvermine-videojs-quality-selector @@ -123,7 +123,7 @@ - videojs-contrib-quality-levels.min.js + videojs-contrib-quality-levels.js @@ -137,7 +137,7 @@ - videojs-http-source-selector.min.js + videojs-http-source-selector.js @@ -151,7 +151,7 @@ - videojs-mobile-ui.min.js + videojs-mobile-ui.js @@ -165,7 +165,7 @@ - videojs-markers.min.js + videojs-markers.js @@ -179,7 +179,7 @@ - videojs-overlay.min.js + videojs/videojs-overlay/videojs-overlay.js @@ -193,7 +193,7 @@ - videojs-share.min.js + videojs-share.js @@ -207,7 +207,7 @@ - videojs-vtt-thumbnails.min.js + videojs-vtt-thumbnails.js @@ -235,7 +235,7 @@ - videojs-vr.js + videojs-vr.js @@ -249,7 +249,7 @@ - video.min.js + video.js diff --git a/videojs-dependencies.yml b/videojs-dependencies.yml new file mode 100644 index 00000000..c1625bfe --- /dev/null +++ b/videojs-dependencies.yml @@ -0,0 +1,45 @@ +video.js: + version: 7.14.3 + shasum: 0b612c09a0a81ef9bce65c710e73291cb06dc32c + +videojs-contrib-quality-levels: + version: 2.1.0 + shasum: 046e9e21ed01043f512b83a1916001d552457083 + +videojs-http-source-selector: + version: 1.1.6 + shasum: 073aadbea0106ba6c98d6b611094dbf8554ffa1f + +videojs-markers: + version: 1.0.1 + shasum: d7f8d804253fd587813271f8db308a22b9f7df34 + +videojs-mobile-ui: + version: 0.6.1 + shasum: 0e146c4c481cbee0729cb5e162e558b455562cd0 + +videojs-overlay: + version: 2.1.4 + shasum: 5a103b25374dbb753eb87960d8360c2e8f39cc05 + +videojs-share: + version: 3.2.1 + shasum: 0a3024b981387b9d21c058c829760a72c14b8ceb + +videojs-vr: + version: 1.8.0 + shasum: 7f2f07f760d8a329c615acd316e49da6ee8edd34 + +videojs-vtt-thumbnails: + version: 0.0.13 + shasum: d1e7d47f4ed80bb52f5fc4f4bad4bfc871f5970f + +silvermine-videojs-quality-selector: + version: 1.1.2 + shasum: 94033ff9ee52ba6da1263b97c9a74d5b3dfdf711 + +# videojs-youtube-annotations: +# github: https://github.com/afrmtbl/videojs-youtube-annotations + + +