mirror of
https://github.com/iv-org/invidious.git
synced 2024-12-05 04:59:12 +05:30
37340f227d
Crystal now supports OpenSSL 3
Reverts 4e629ca858
224 lines
6.6 KiB
Crystal
Executable File
224 lines
6.6 KiB
Crystal
Executable File
require "http"
|
|
require "yaml"
|
|
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 && Digest::SHA1.hexdigest(data) != @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
|
|
ARGV[0].split(",") { |str| parser_args << str.strip }
|
|
else
|
|
parser_args = ARGV
|
|
end
|
|
|
|
# Taken from https://crystal-lang.org/api/1.1.1/OptionParser.html
|
|
minified = false
|
|
skip_checksum = false
|
|
|
|
OptionParser.parse(parser_args) 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("--skip-checksum", "Skips the checksum validation of downloaded files") { skip_checksum = 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
|
|
|
|
# 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.
|
|
|
|
dependencies_to_install = [] of String
|
|
|
|
required_dependencies.keys.each do |dep|
|
|
dep = dep.as_s
|
|
path = "assets/videojs/#{dep}"
|
|
|
|
# Check for missing dependencies
|
|
#
|
|
# Does the directory exist?
|
|
# Does the Javascript file exist?
|
|
# Does the CSS file exist?
|
|
#
|
|
# videojs-contrib-quality-levels.js is the only dependency that does not come with a CSS file so
|
|
# we skip the check there
|
|
if !Dir.exists?(path)
|
|
Dir.mkdir(path)
|
|
next dependencies_to_install << dep
|
|
elsif !(File.exists?("#{path}/#{dep}.js") || File.exists?("#{path}/versions.yml"))
|
|
next dependencies_to_install << dep
|
|
elsif dep != "videojs-contrib-quality-levels" && !File.exists?("#{path}/#{dep}.css")
|
|
next dependencies_to_install << dep
|
|
end
|
|
|
|
# Check if we need to update the dependency
|
|
|
|
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
|
|
# Clear directory
|
|
{"*.js", "*.css"}.each do |file_types|
|
|
Dir.glob("#{path}/#{file_types}").each do |file_path|
|
|
File.delete(file_path)
|
|
end
|
|
end
|
|
|
|
dependencies_to_install << dep
|
|
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 | Exception).new
|
|
|
|
dependencies_to_install.each do |dep|
|
|
spawn do
|
|
dependency = Dependency.new(required_dependencies, dep, tmp_dir_path, minified, skip_checksum)
|
|
dependency.fetch
|
|
channel.send(dep)
|
|
rescue ex
|
|
channel.send(ex)
|
|
end
|
|
end
|
|
|
|
if dependencies_to_install.empty?
|
|
puts "#{"Player".colorize(:blue)} #{"dependencies".colorize(:green)} are satisfied"
|
|
else
|
|
puts "#{"Resolving".colorize(:green)} #{"player".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
|
|
|
|
# Cleanup
|
|
`rm -rf #{tmp_dir_path}`
|