Compare commits
8 commits
master
...
external-p
Author | SHA1 | Date | |
---|---|---|---|
e1a1bf0f79 | |||
7ded7455b0 | |||
53f0a5b1e0 | |||
34a11fe1bb | |||
2db9396dea | |||
|
0c3e5baab0 | ||
73ba53a327 | |||
00bcf53d0f |
13 changed files with 130 additions and 13 deletions
|
@ -51,6 +51,9 @@ videojs.Vhs.xhr.beforeRequest = function(options) {
|
|||
return options;
|
||||
};
|
||||
|
||||
videojs.Vhs.GOAL_BUFFER_LENGTH = 20;
|
||||
videojs.Vhs.MAX_GOAL_BUFFER_LENGTH = 30;
|
||||
|
||||
var player = videojs('player', options);
|
||||
|
||||
player.on('error', function () {
|
||||
|
|
|
@ -222,6 +222,15 @@ https_only: false
|
|||
##
|
||||
#log_level: Info
|
||||
|
||||
##
|
||||
## Enables colors in logs. Useful for debugging purposes
|
||||
## This is overridden if "-k" or "--colorize"
|
||||
## are passed on the command line.
|
||||
##
|
||||
## Accepted values: true, false
|
||||
## Default: false
|
||||
##
|
||||
#colorize_logs: false
|
||||
|
||||
# -----------------------------
|
||||
# Features
|
||||
|
|
|
@ -115,6 +115,9 @@ Kemal.config.extra_options do |parser|
|
|||
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
|
||||
|
@ -131,7 +134,7 @@ 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)
|
||||
LOGGER = Invidious::LogHandler.new(OUTPUT, CONFIG.log_level, CONFIG.colorize_logs)
|
||||
|
||||
# Check table integrity
|
||||
Invidious::Database.check_integrity(CONFIG)
|
||||
|
|
|
@ -66,6 +66,8 @@ class Config
|
|||
property output : String = "STDOUT"
|
||||
# Default log level, valid YAML values are ints and strings, see src/invidious/helpers/logger.cr
|
||||
property log_level : LogLevel = LogLevel::Info
|
||||
# Enables colors in logs. Useful for debugging purposes
|
||||
property colorize_logs : Bool = false
|
||||
# Database configuration with separate parameters (username, hostname, etc)
|
||||
property db : DBConfig? = nil
|
||||
|
||||
|
@ -167,6 +169,11 @@ class Config
|
|||
# The max resolution the Instance can offer
|
||||
property max_dash_resolution : Int32?
|
||||
|
||||
# List of names of the backends
|
||||
property backends : Array(String) = [] of String
|
||||
|
||||
property external_videoplayback_proxy : String?
|
||||
|
||||
# Materialious redirects
|
||||
property materialious_domain : String?
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require "colorize"
|
||||
|
||||
enum LogLevel
|
||||
All = 0
|
||||
Trace = 1
|
||||
|
@ -10,7 +12,7 @@ enum LogLevel
|
|||
end
|
||||
|
||||
class Invidious::LogHandler < Kemal::BaseLogHandler
|
||||
def initialize(@io : IO = STDOUT, @level = LogLevel::Debug)
|
||||
def initialize(@io : IO = STDOUT, @level = LogLevel::Debug, @color : Bool = true)
|
||||
end
|
||||
|
||||
def call(context : HTTP::Server::Context)
|
||||
|
@ -39,10 +41,23 @@ class Invidious::LogHandler < Kemal::BaseLogHandler
|
|||
@io.flush
|
||||
end
|
||||
|
||||
def color(level)
|
||||
case level
|
||||
when LogLevel::Trace then :cyan
|
||||
when LogLevel::Debug then :green
|
||||
when LogLevel::Info then :white
|
||||
when LogLevel::Warn then :yellow
|
||||
when LogLevel::Error then :red
|
||||
when LogLevel::Fatal then :magenta
|
||||
else :default
|
||||
end
|
||||
end
|
||||
|
||||
{% for level in %w(trace debug info warn error fatal) %}
|
||||
def {{level.id}}(message : String)
|
||||
if LogLevel::{{level.id.capitalize}} >= @level
|
||||
puts("#{Time.utc} [{{level.id}}] #{message}")
|
||||
puts("#{Time.utc} [{{level.id}}] #{message}".colorize(color(LogLevel::{{level.id.capitalize}})).toggle(@color))
|
||||
|
||||
end
|
||||
end
|
||||
{% end %}
|
||||
|
|
|
@ -176,7 +176,9 @@ module Invidious::SigHelper
|
|||
|
||||
@conn : Connection
|
||||
|
||||
def initialize(uri_or_path)
|
||||
@uri_or_path : String
|
||||
|
||||
def initialize(@uri_or_path)
|
||||
@conn = Connection.new(uri_or_path)
|
||||
listen
|
||||
end
|
||||
|
@ -186,10 +188,27 @@ module Invidious::SigHelper
|
|||
|
||||
LOGGER.debug("SigHelper: Multiplexor listening")
|
||||
|
||||
# TODO: reopen socket if unexpectedly closed
|
||||
spawn do
|
||||
loop do
|
||||
receive_data
|
||||
begin
|
||||
receive_data
|
||||
# Handle all errors
|
||||
rescue ex
|
||||
LOGGER.info("SigHelper: Connection to helper died with '#{ex.message}' trying to reconnect...")
|
||||
# We close the socket because for some reason is not closed.
|
||||
@conn.close
|
||||
loop do
|
||||
begin
|
||||
@conn = Connection.new(@uri_or_path)
|
||||
LOGGER.info("SigHelper: Reconnected to SigHelper!")
|
||||
rescue ex
|
||||
LOGGER.debug("SigHelper: Reconnection to helper unsuccessful with error '#{ex.message}' retrying")
|
||||
sleep 0.5
|
||||
next
|
||||
end
|
||||
break if !@conn.closed?
|
||||
end
|
||||
end
|
||||
Fiber.yield
|
||||
end
|
||||
end
|
||||
|
@ -306,6 +325,11 @@ module Invidious::SigHelper
|
|||
return @socket.closed?
|
||||
end
|
||||
|
||||
def remote_address : Socket::IPAddress
|
||||
|
||||
return @socket.remote_address
|
||||
end
|
||||
|
||||
def close : Nil
|
||||
@socket.close if !@socket.closed?
|
||||
end
|
||||
|
|
|
@ -35,7 +35,11 @@ module Invidious::Routes::API::Manifest
|
|||
|
||||
if local
|
||||
uri = URI.parse(url)
|
||||
url = "#{HOST_URL}#{uri.request_target}host/#{uri.host}/"
|
||||
if CONFIG.external_videoplayback_proxy
|
||||
url = "#{CONFIG.external_videoplayback_proxy}#{uri.request_target}host/#{uri.host}/"
|
||||
else
|
||||
url = "#{HOST_URL}#{uri.request_target}host/#{uri.host}/"
|
||||
end
|
||||
end
|
||||
|
||||
"<BaseURL>#{url}</BaseURL>"
|
||||
|
@ -48,21 +52,24 @@ module Invidious::Routes::API::Manifest
|
|||
|
||||
if local
|
||||
adaptive_fmts.each do |fmt|
|
||||
fmt["url"] = JSON::Any.new("#{HOST_URL}#{URI.parse(fmt["url"].as_s).request_target}")
|
||||
if CONFIG.external_videoplayback_proxy
|
||||
fmt["url"] = JSON::Any.new("#{CONFIG.external_videoplayback_proxy}#{URI.parse(fmt["url"].as_s).request_target}")
|
||||
else
|
||||
fmt["url"] = JSON::Any.new("#{HOST_URL}#{URI.parse(fmt["url"].as_s).request_target}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
audio_streams = video.audio_streams.sort_by { |stream| {stream["bitrate"].as_i} }.reverse!
|
||||
video_streams = video.video_streams.sort_by { |stream| {stream["width"].as_i, stream["fps"].as_i} }.reverse!
|
||||
|
||||
# Removes all the resolutions with a height higher than CONFIG.max_dash_resolution
|
||||
# Removes all the resolutions with a height higher than CONFIG.max_dash_resolution
|
||||
if CONFIG.max_dash_resolution
|
||||
video_streams.reject! do |z|
|
||||
(z["height"].as_i > CONFIG.max_dash_resolution.not_nil!) if z["height"]?
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
manifest = XML.build(indent: " ", encoding: "UTF-8") do |xml|
|
||||
xml.element("MPD", "xmlns": "urn:mpeg:dash:schema:mpd:2011",
|
||||
"profiles": "urn:mpeg:dash:profile:full:2011", minBufferTime: "PT1.5S", type: "static",
|
||||
|
|
|
@ -28,6 +28,12 @@ module Invidious::Routes::BeforeAll
|
|||
extra_media_csp = ""
|
||||
end
|
||||
|
||||
if CONFIG.external_videoplayback_proxy
|
||||
external_videoplayback_proxy = " #{CONFIG.external_videoplayback_proxy}"
|
||||
else
|
||||
external_videoplayback_proxy = ""
|
||||
end
|
||||
|
||||
# Only allow the pages at /embed/* to be embedded
|
||||
if env.request.resource.starts_with?("/embed")
|
||||
frame_ancestors = "'self' file: http: https:"
|
||||
|
@ -43,7 +49,7 @@ module Invidious::Routes::BeforeAll
|
|||
"style-src 'self' 'unsafe-inline'",
|
||||
"img-src 'self' data:",
|
||||
"font-src 'self' data:",
|
||||
"connect-src 'self'",
|
||||
"connect-src 'self'" + external_videoplayback_proxy,
|
||||
"manifest-src 'self'",
|
||||
"media-src 'self' blob:" + extra_media_csp,
|
||||
"child-src 'self' blob:",
|
||||
|
|
18
src/invidious/routes/switch_backend.cr
Normal file
18
src/invidious/routes/switch_backend.cr
Normal file
|
@ -0,0 +1,18 @@
|
|||
{% skip_file if flag?(:api_only) %}
|
||||
|
||||
module Invidious::Routes::BackendSwitcher
|
||||
def self.switch(env)
|
||||
referer = get_referer(env)
|
||||
backend_id = env.params.query["backend_id"]
|
||||
|
||||
# Checks if there is any alternative domain, like a second domain name,
|
||||
# TOR or I2P address
|
||||
if alt = CONFIG.alternative_domains.index(env.request.headers["Host"])
|
||||
env.response.cookies["SERVER_ID"] = Invidious::User::Cookies.server_id(CONFIG.alternative_domains[alt], backend_id)
|
||||
else
|
||||
env.response.cookies["SERVER_ID"] = Invidious::User::Cookies.server_id(CONFIG.domain, backend_id)
|
||||
end
|
||||
|
||||
env.redirect referer
|
||||
end
|
||||
end
|
|
@ -120,7 +120,7 @@ module Invidious::Routes::Watch
|
|||
fmt_stream = video.fmt_stream
|
||||
adaptive_fmts = video.adaptive_fmts
|
||||
|
||||
# Removes all the resolutions with a height higher than CONFIG.max_dash_resolution
|
||||
# Removes all the resolutions with a height higher than CONFIG.max_dash_resolution
|
||||
if CONFIG.max_dash_resolution
|
||||
adaptive_fmts.reject! do |z|
|
||||
(z["height"].as_i > CONFIG.max_dash_resolution.not_nil!) if z["height"]?
|
||||
|
@ -135,7 +135,7 @@ module Invidious::Routes::Watch
|
|||
video_streams = video.video_streams
|
||||
audio_streams = video.audio_streams
|
||||
|
||||
# Removes all the resolutions with a height higher than CONFIG.max_dash_resolution
|
||||
# Removes all the resolutions with a height higher than CONFIG.max_dash_resolution
|
||||
if CONFIG.max_dash_resolution
|
||||
video_streams.reject! do |z|
|
||||
(z["height"].as_i > CONFIG.max_dash_resolution.not_nil!) if z["height"]?
|
||||
|
|
|
@ -21,6 +21,7 @@ module Invidious::Routing
|
|||
get "/privacy", Routes::Misc, :privacy
|
||||
get "/licenses", Routes::Misc, :licenses
|
||||
get "/redirect", Routes::Misc, :cross_instance_redirect
|
||||
get "/switchbackend", Routes::BackendSwitcher, :switch
|
||||
|
||||
self.register_channel_routes
|
||||
self.register_watch_routes
|
||||
|
|
|
@ -45,5 +45,18 @@ struct Invidious::User
|
|||
samesite: HTTP::Cookie::SameSite::Lax
|
||||
)
|
||||
end
|
||||
|
||||
# Server ID (SERVER_ID) cookie used for Sticky Sessions
|
||||
# Parameter "domain" comes from the global config
|
||||
def server_id(domain : String?, server_id) : HTTP::Cookie
|
||||
return HTTP::Cookie.new(
|
||||
name: "SERVER_ID",
|
||||
domain: domain,
|
||||
value: server_id,
|
||||
secure: false,
|
||||
http_only: true,
|
||||
samesite: HTTP::Cookie::SameSite::Lax
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -104,6 +104,17 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<% if CONFIG.backends %>
|
||||
<div class="h-box">
|
||||
<b>Switch Backend:</b>
|
||||
<% CONFIG.backends.each do | backend | %>
|
||||
<a href="/switchbackend?backend_id=<%= backend %>">
|
||||
Backend<%= HTML.escape(backend) %>
|
||||
</a> |
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if CONFIG.banner %>
|
||||
<div class="h-box">
|
||||
<h3><%= CONFIG.banner %></h3>
|
||||
|
|
Loading…
Reference in a new issue