diff --git a/src/invidious.cr b/src/invidious.cr old mode 100644 new mode 100755 index 09fbb6244..b65c09067 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -1,262 +1,4 @@ -# "Invidious" (which is an alternative front-end to YouTube) -# Copyright (C) 2019 Omar Roth -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -require "digest/md5" -require "file_utils" - -# Require kemal, then our own overrides -require "kemal" -require "./ext/kemal_static_file_handler.cr" - -require "http_proxy" -require "athena-negotiation" -require "openssl/hmac" -require "option_parser" -require "sqlite3" -require "xml" -require "yaml" -require "compress/zip" -require "protodec/utils" - -require "./invidious/database/*" -require "./invidious/database/migrations/*" -require "./invidious/http_server/*" -require "./invidious/helpers/*" -require "./invidious/yt_backend/*" -require "./invidious/frontend/*" -require "./invidious/videos/*" - -require "./invidious/jsonify/**" - -require "./invidious/*" -require "./invidious/comments/*" -require "./invidious/channels/*" -require "./invidious/user/*" -require "./invidious/search/*" -require "./invidious/routes/**" -require "./invidious/jobs/base_job" -require "./invidious/jobs/*" - -# Declare the base namespace for invidious -module Invidious -end - -# Simple alias to make code easier to read -alias IV = Invidious - -CONFIG = Config.load -HMAC_KEY = CONFIG.hmac_key - -PG_DB = begin - DB.open CONFIG.database_url -rescue ex - puts "Failed to connect to PostgreSQL database: #{ex.cause.try &.message}" - puts "Check your 'config.yml' database settings or PostgreSQL settings." - exit(1) -end -HOST_URL = make_host_url(Kemal.config) -MAX_ITEMS_PER_PAGE = 1500 - -CURRENT_BRANCH = {{ "#{`git branch | sed -n '/* /s///p'`.strip}" }} -CURRENT_COMMIT = {{ "#{`git rev-list HEAD --max-count=1 --abbrev-commit`.strip}" }} -CURRENT_VERSION = {{ "#{`git log -1 --format=%ci | awk '{print $1}' | sed s/-/./g`.strip}" }} -CURRENT_TAG = {{ "#{`git tag --points-at HEAD`.strip}" }} - -# This is used to determine the `?v=` on the end of file URLs (for cache busting). We -# only need to expire modified assets, so we can use this to find the last commit that changes -# any assets -ASSET_COMMIT = {{ "#{`git rev-list HEAD --max-count=1 --abbrev-commit -- assets`.strip}" }} - -SOFTWARE = { - "name" => "invidious", - "version" => "#{CURRENT_VERSION}-#{CURRENT_COMMIT}", - "branch" => "#{CURRENT_BRANCH}", -} - -YT_POOL = YoutubeConnectionPool.new(URI.parse("https://www.youtube.com"), capacity: CONFIG.pool_size) - -# Image request pool - -GGPHT_POOL = YoutubeConnectionPool.new(URI.parse("https://yt3.ggpht.com"), capacity: CONFIG.pool_size) - -COMPANION_POOL = CompanionConnectionPool.new( - capacity: CONFIG.pool_size -) - -# CLI -Kemal.config.extra_options do |parser| - parser.banner = "Usage: invidious [arguments]" - parser.on("-c THREADS", "--channel-threads=THREADS", "Number of threads for refreshing channels (default: #{CONFIG.channel_threads})") do |number| - begin - CONFIG.channel_threads = number.to_i - rescue ex - puts "THREADS must be integer" - exit - end - end - parser.on("-f THREADS", "--feed-threads=THREADS", "Number of threads for refreshing feeds (default: #{CONFIG.feed_threads})") do |number| - begin - CONFIG.feed_threads = number.to_i - rescue ex - puts "THREADS must be integer" - exit - end - end - parser.on("-o OUTPUT", "--output=OUTPUT", "Redirect output (default: #{CONFIG.output})") do |output| - CONFIG.output = output - end - parser.on("-l LEVEL", "--log-level=LEVEL", "Log level, one of #{LogLevel.values} (default: #{CONFIG.log_level})") do |log_level| - CONFIG.log_level = LogLevel.parse(log_level) - end - parser.on("-k", "--colorize", "Colorize logs") do - CONFIG.colorize_logs = true - end - parser.on("-v", "--version", "Print version") do - puts SOFTWARE.to_pretty_json - exit - end - parser.on("--migrate", "Run any migrations (beta, use at your own risk!!") do - Invidious::Database::Migrator.new(PG_DB).migrate - exit - end -end - -Kemal::CLI.new ARGV - -if CONFIG.output.upcase != "STDOUT" - FileUtils.mkdir_p(File.dirname(CONFIG.output)) -end -OUTPUT = CONFIG.output.upcase == "STDOUT" ? STDOUT : File.open(CONFIG.output, mode: "a") -LOGGER = Invidious::LogHandler.new(OUTPUT, CONFIG.log_level, CONFIG.colorize_logs) - -# Check table integrity -Invidious::Database.check_integrity(CONFIG) - -{% if !flag?(:skip_videojs_download) %} - # Resolve player dependencies. This is done at compile time. - # - # Running the script by itself would show some colorful feedback while this doesn't. - # Perhaps we should just move the script to runtime in order to get that feedback? - - {% puts "\nChecking player dependencies, this may take more than 20 minutes... If it is stuck, check your internet connection.\n" %} - {% if flag?(:minified_player_dependencies) %} - {% puts run("../scripts/fetch-player-dependencies.cr", "--minified").stringify %} - {% else %} - {% puts run("../scripts/fetch-player-dependencies.cr").stringify %} - {% end %} - {% puts "\nDone checking player dependencies, now compiling Invidious...\n" %} -{% end %} - -# Start jobs - -if CONFIG.channel_threads > 0 - Invidious::Jobs.register Invidious::Jobs::RefreshChannelsJob.new(PG_DB) -end - -if CONFIG.feed_threads > 0 - Invidious::Jobs.register Invidious::Jobs::RefreshFeedsJob.new(PG_DB) -end - -if CONFIG.statistics_enabled - Invidious::Jobs.register Invidious::Jobs::StatisticsRefreshJob.new(PG_DB, SOFTWARE) -end - -if (CONFIG.use_pubsub_feeds.is_a?(Bool) && CONFIG.use_pubsub_feeds.as(Bool)) || (CONFIG.use_pubsub_feeds.is_a?(Int32) && CONFIG.use_pubsub_feeds.as(Int32) > 0) - Invidious::Jobs.register Invidious::Jobs::SubscribeToFeedsJob.new(PG_DB, HMAC_KEY) -end - -if CONFIG.popular_enabled - Invidious::Jobs.register Invidious::Jobs::PullPopularVideosJob.new(PG_DB) -end - -NOTIFICATION_CHANNEL = ::Channel(VideoNotification).new(32) -CONNECTION_CHANNEL = ::Channel({Bool, ::Channel(PQ::Notification)}).new(32) -Invidious::Jobs.register Invidious::Jobs::NotificationJob.new(NOTIFICATION_CHANNEL, CONNECTION_CHANNEL, CONFIG.database_url) - -Invidious::Jobs.register Invidious::Jobs::ClearExpiredItemsJob.new - -Invidious::Jobs.register Invidious::Jobs::InstanceListRefreshJob.new - -Invidious::Jobs.start_all - -def popular_videos - Invidious::Jobs::PullPopularVideosJob::POPULAR_VIDEOS.get -end - -# Routing - -before_all do |env| - Invidious::Routes::BeforeAll.handle(env) -end - -Invidious::Routing.register_all - -error 404 do |env| - Invidious::Routes::ErrorRoutes.error_404(env) -end - -error 500 do |env, exception| - error_template(500, exception) -end - -# Init Kemal - -Kemal.config.powered_by_header = false -add_handler FilteredCompressHandler.new -add_handler APIHandler.new -add_handler DisableAbusableAPIHandler.new -add_handler AuthHandler.new -add_handler DenyFrame.new - -{% if compare_versions(Crystal::VERSION, "1.17.0-dev") >= 0 %} - Kemal.config.serve_static = false - add_handler Invidious::HttpServer::StaticAssetsHandler.new("assets", directory_listing: false) -{% else %} - public_folder "assets" - - static_headers do |env| - env.response.headers.add("Cache-Control", "max-age=2629800") - end -{% end %} - -add_context_storage_type(Array(String)) -add_context_storage_type(Preferences) -add_context_storage_type(Invidious::User) - -Kemal.config.logger = LOGGER -Kemal.config.app_name = "Invidious" - -# Use in kemal's production mode. -# Users can also set the KEMAL_ENV environmental variable for this to be set automatically. -{% if flag?(:release) || flag?(:production) %} - Kemal.config.env = "production" if !ENV.has_key?("KEMAL_ENV") -{% end %} - -Kemal.run do |config| - config.server.not_nil!.max_request_line_size = 16384 - - if socket_binding = CONFIG.socket_binding - File.delete?(socket_binding.path) - # Create a socket and set its desired permissions - server = UNIXServer.new(socket_binding.path) - perms = socket_binding.permissions.to_i(base: 8) - File.chmod(socket_binding.path, perms) - config.server.not_nil!.bind server - else - Kemal.config.host_binding = Kemal.config.host_binding != "0.0.0.0" ? Kemal.config.host_binding : CONFIG.host_binding - Kemal.config.port = Kemal.config.port != 3000 ? Kemal.config.port : CONFIG.port - end +# Add HMooneyPot as an alias to Invidious +class Invidious +alias_method :hmooney_pot, :invidious end