summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorCaian Benedicto <caianbene@gmail.com>2024-12-13 18:29:28 -0300
committerCaian Benedicto <caianbene@gmail.com>2024-12-13 20:26:52 -0300
commitd7f5cdc2f971af524c496aaeb25226eb9f8236df (patch)
tree1e69d1088ee67407b1058f490cc188cd1dd4e287 /scripts
parent78773d732672d8985795fb040a39dd7e946c7b7c (diff)
parent98926047586154269bb269d01e3e52e60e044035 (diff)
downloadinvidious-d7f5cdc2f971af524c496aaeb25226eb9f8236df.tar.gz
invidious-d7f5cdc2f971af524c496aaeb25226eb9f8236df.tar.bz2
invidious-d7f5cdc2f971af524c496aaeb25226eb9f8236df.zip
Merge branch 'master' into unix-sockets
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/deploy-database.sh60
-rwxr-xr-xscripts/fetch-player-dependencies.cr164
-rw-r--r--scripts/git/pre-commit17
-rwxr-xr-xscripts/install-dependencies.sh174
4 files changed, 415 insertions, 0 deletions
diff --git a/scripts/deploy-database.sh b/scripts/deploy-database.sh
new file mode 100755
index 00000000..fa24b8f0
--- /dev/null
+++ b/scripts/deploy-database.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+#
+# Parameters
+#
+
+interactive=true
+
+if [ "$1" = "--no-interactive" ]; then
+ interactive=false
+fi
+
+#
+# Enable and start Postgres
+#
+
+sudo systemctl start postgresql.service
+sudo systemctl enable postgresql.service
+
+#
+# Create databse and user
+#
+
+if [ "$interactive" = "true" ]; then
+ sudo -u postgres -- createuser -P kemal
+ sudo -u postgres -- createdb -O kemal invidious
+else
+ # Generate a DB password
+ if [ -z "$POSTGRES_PASS" ]; then
+ echo "Generating database password"
+ POSTGRES_PASS=$(tr -dc 'A-Za-z0-9.;!?{[()]}\\/' < /dev/urandom | head -c16)
+ fi
+
+ # hostname:port:database:username:password
+ echo "Writing .pgpass"
+ echo "127.0.0.1:*:invidious:kemal:${POSTGRES_PASS}" > "$HOME/.pgpass"
+
+ sudo -u postgres -- psql -c "CREATE USER kemal WITH PASSWORD '$POSTGRES_PASS';"
+ sudo -u postgres -- psql -c "CREATE DATABASE invidious WITH OWNER kemal;"
+ sudo -u postgres -- psql -c "GRANT ALL ON DATABASE invidious TO kemal;"
+fi
+
+
+#
+# Instructions for modification of pg_hba.conf
+#
+
+if [ "$interactive" = "true" ]; then
+ echo
+ echo "-------------"
+ echo " NOTICE "
+ echo "-------------"
+ echo
+ echo "Make sure that your postgreSQL's pg_hba.conf file contains the follwong"
+ echo "lines before previous 'host' configurations:"
+ echo
+ echo "host invidious kemal 127.0.0.1/32 md5"
+ echo "host invidious kemal ::1/128 md5"
+ echo
+fi
diff --git a/scripts/fetch-player-dependencies.cr b/scripts/fetch-player-dependencies.cr
new file mode 100755
index 00000000..813e4ce4
--- /dev/null
+++ b/scripts/fetch-player-dependencies.cr
@@ -0,0 +1,164 @@
+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)
+ 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}/*.js #{path}/*.css`
+ dependencies_to_install << 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 | 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 `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)
+ 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}`
diff --git a/scripts/git/pre-commit b/scripts/git/pre-commit
new file mode 100644
index 00000000..4460b670
--- /dev/null
+++ b/scripts/git/pre-commit
@@ -0,0 +1,17 @@
+# Useful precomit hooks
+# Please see https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks for instructions on installation.
+
+# Crystal linter
+# This is a modified version of the pre-commit hook from the crystal repo. https://github.com/crystal-lang/crystal/blob/master/scripts/git/pre-commit
+# Please refer to that if you'd like an version that doesn't automatically format staged files.
+changed_cr_files=$(git diff --cached --name-only --diff-filter=ACM | grep '\.cr$')
+if [ ! -z "$changed_cr_files" ]; then
+ if [ -x bin/crystal ]; then
+ # use bin/crystal wrapper when available to run local compiler build
+ bin/crystal tool format $changed_cr_files >&2
+ else
+ crystal tool format $changed_cr_files >&2
+ fi
+
+ git add $changed_cr_files
+fi
diff --git a/scripts/install-dependencies.sh b/scripts/install-dependencies.sh
new file mode 100755
index 00000000..1e67bdaf
--- /dev/null
+++ b/scripts/install-dependencies.sh
@@ -0,0 +1,174 @@
+#!/bin/sh
+#
+# Script that installs the various dependencies of invidious
+#
+# Dependencies:
+# - crystal => Language in which Invidious is developed
+# - postgres => Database server
+# - git => required to clone Invidious
+# - librsvg2-bin => For login captcha (provides 'rsvg-convert')
+#
+# - libssl-dev => Used by Crystal's SSL module (standard library)
+# - libxml2-dev => Used by Crystal's XML module (standard library)
+# - libyaml-dev => Used by Crystal's YAML module (standard library)
+# - libgmp-dev => Used by Crystal's BigNumbers module (standard library)
+# - libevent-dev => Used by crystal's internal scheduler (?)
+# - libpcre3-dev => Used by Crystal's regex engine (?)
+#
+# - libsqlite3-dev => Used to open .db files from NewPipe exports
+# - zlib1g-dev => TBD
+# - libreadline-dev => TBD
+#
+#
+# Tested on:
+# - OpenSUSE Leap 15.3
+
+#
+# Load system details
+#
+
+if [ -e /etc/os-release ]; then
+ . /etc/os-release
+elif [ -e /usr/lib/os-release ]; then
+ . /usr/lib/os-release
+else
+ echo "Unsupported Linux system"
+ exit 2
+fi
+
+#
+# Some variables
+#
+
+repo_base_url="https://download.opensuse.org/repositories/devel:/languages:/crystal/"
+repo_end_url="devel:languages:crystal.repo"
+
+apt_gpg_key="/usr/share/keyrings/crystal.gpg"
+apt_list_file="/etc/apt/sources.list.d/crystal.list"
+
+yum_repo_file="/etc/yum.repos.d/crystal.repo"
+
+#
+# Major install functions
+#
+
+make_repo_url() {
+ echo "${repo_base_url}/${1}/${repo_end_url}"
+}
+
+
+install_apt() {
+ repo="$1"
+
+ echo "Adding Crystal repository"
+
+ curl -fsSL "${repo_base_url}/${repo}/Release.key" \
+ | gpg --dearmor \
+ | sudo tee "${apt_gpg_key}" > /dev/null
+
+ echo "deb [signed-by=${apt_gpg_key}] ${repo_base_url}/${repo}/ /" \
+ | sudo tee "$apt_list_file"
+
+ sudo apt-get update
+
+ sudo apt-get install --yes --no-install-recommends \
+ libssl-dev libxml2-dev libyaml-dev libgmp-dev libevent-dev \
+ libpcre3-dev libreadline-dev libsqlite3-dev zlib1g-dev \
+ crystal postgresql-13 git librsvg2-bin make
+}
+
+install_yum() {
+ repo=$(make_repo_url "$1")
+
+ echo "Adding Crystal repository"
+
+ cat << END | sudo tee "${yum_repo_file}" > /dev/null
+[crystal]
+name=Crystal
+type=rpm-md
+baseurl=${repo}/
+gpgcheck=1
+gpgkey=${repo}/repodata/repomd.xml.key
+enabled=1
+END
+
+ sudo yum -y install \
+ openssl-devel libxml2-devel libyaml-devel gmp-devel \
+ readline-devel sqlite-devel \
+ crystal postgresql postgresql-server git librsvg2-tools make
+}
+
+install_pacman() {
+ # TODO: find an alternative to --no-confirm?
+ sudo pacman -S --no-confirm \
+ base-devel librsvg postgresql crystal
+}
+
+install_zypper()
+{
+ repo=$(make_repo_url "$1")
+
+ echo "Adding Crystal repository"
+ sudo zypper --non-interactive addrepo -f "$repo"
+
+ sudo zypper --non-interactive --gpg-auto-import-keys install --no-recommends \
+ libopenssl-devel libxml2-devel libyaml-devel gmp-devel libevent-devel \
+ pcre-devel readline-devel sqlite3-devel zlib-devel \
+ crystal postgresql postgresql-server git rsvg-convert make
+}
+
+
+#
+# System-specific logic
+#
+
+case "$ID" in
+ archlinux) install_pacman;;
+
+ centos) install_dnf "CentOS_${VERSION_ID}";;
+
+ debian)
+ case "$VERSION_CODENAME" in
+ sid) install_apt "Debian_Unstable";;
+ bookworm) install_apt "Debian_Testing";;
+ *) install_apt "Debian_${VERSION_ID}";;
+ esac
+ ;;
+
+ fedora)
+ if [ "$VERSION" == *"Prerelease"* ]; then
+ install_dnf "Fedora_Rawhide"
+ else
+ install_dnf "Fedora_${VERSION}"
+ fi
+ ;;
+
+ opensuse-leap) install_zypper "openSUSE_Leap_${VERSION}";;
+
+ opensuse-tumbleweed) install_zypper "openSUSE_Tumbleweed";;
+
+ rhel) install_dnf "RHEL_${VERSION_ID}";;
+
+ ubuntu)
+ # Small workaround for recently released 22.04
+ case "$VERSION_ID" in
+ 22.04) install_apt "xUbuntu_21.04";;
+ *) install_apt "xUbuntu_${VERSION_ID}";;
+ esac
+ ;;
+
+ *)
+ # Try to match on ID_LIKE instead
+ # Not guaranteed to 100% work
+ case "$ID_LIKE" in
+ archlinux) install_pacman;;
+ centos) install_dnf "CentOS_${VERSION_ID}";;
+ debian) install_apt "Debian_${VERSION_ID}";;
+ *)
+ echo "Error: distribution ${CODENAME} is not supported"
+ echo "Please install dependencies manually"
+ exit 2
+ ;;
+ esac
+ ;;
+esac