mirror of
https://gitea.invidious.io/iv-org/invidious-copy-2022-03-16.git
synced 2024-08-15 00:53:18 +00:00
Move preferences/config-related code to separate files
This commit is contained in:
parent
7ddab5b8cd
commit
22cc8f4603
5 changed files with 606 additions and 596 deletions
150
src/invidious/config.cr
Normal file
150
src/invidious/config.cr
Normal file
|
@ -0,0 +1,150 @@
|
|||
#
|
||||
# This file contains the server config data structures and
|
||||
# all the associated validation/parsing routines.
|
||||
#
|
||||
|
||||
struct DBConfig
|
||||
include YAML::Serializable
|
||||
|
||||
property user : String
|
||||
property password : String
|
||||
|
||||
property host : String
|
||||
property port : Int32
|
||||
|
||||
property dbname : String
|
||||
end
|
||||
|
||||
class Config
|
||||
include YAML::Serializable
|
||||
|
||||
property channel_threads : Int32 = 1 # Number of threads to use for crawling videos from channels (for updating subscriptions)
|
||||
property feed_threads : Int32 = 1 # Number of threads to use for updating feeds
|
||||
property output : String = "STDOUT" # Log file path or STDOUT
|
||||
property log_level : LogLevel = LogLevel::Info # Default log level, valid YAML values are ints and strings, see src/invidious/helpers/logger.cr
|
||||
property db : DBConfig? = nil # Database configuration with separate parameters (username, hostname, etc)
|
||||
|
||||
@[YAML::Field(converter: Preferences::URIConverter)]
|
||||
property database_url : URI = URI.parse("") # Database configuration using 12-Factor "Database URL" syntax
|
||||
property decrypt_polling : Bool = true # Use polling to keep decryption function up to date
|
||||
property full_refresh : Bool = false # Used for crawling channels: threads should check all videos uploaded by a channel
|
||||
property https_only : Bool? # Used to tell Invidious it is behind a proxy, so links to resources should be https://
|
||||
property hmac_key : String? # HMAC signing key for CSRF tokens and verifying pubsub subscriptions
|
||||
property domain : String? # Domain to be used for links to resources on the site where an absolute URL is required
|
||||
property use_pubsub_feeds : Bool | Int32 = false # Subscribe to channels using PubSubHubbub (requires domain, hmac_key)
|
||||
property popular_enabled : Bool = true
|
||||
property captcha_enabled : Bool = true
|
||||
property login_enabled : Bool = true
|
||||
property registration_enabled : Bool = true
|
||||
property statistics_enabled : Bool = false
|
||||
property admins : Array(String) = [] of String
|
||||
property external_port : Int32? = nil
|
||||
property default_user_preferences : ConfigPreferences = ConfigPreferences.from_yaml("")
|
||||
property dmca_content : Array(String) = [] of String # For compliance with DMCA, disables download widget using list of video IDs
|
||||
property check_tables : Bool = false # Check table integrity, automatically try to add any missing columns, create tables, etc.
|
||||
property cache_annotations : Bool = false # Cache annotations requested from IA, will not cache empty annotations or annotations that only contain cards
|
||||
property banner : String? = nil # Optional banner to be displayed along top of page for announcements, etc.
|
||||
property hsts : Bool? = true # Enables 'Strict-Transport-Security'. Ensure that `domain` and all subdomains are served securely
|
||||
property disable_proxy : Bool? | Array(String)? = false # Disable proxying server-wide: options: 'dash', 'livestreams', 'downloads', 'local'
|
||||
|
||||
@[YAML::Field(converter: Preferences::FamilyConverter)]
|
||||
property force_resolve : Socket::Family = Socket::Family::UNSPEC # Connect to YouTube over 'ipv6', 'ipv4'. Will sometimes resolve fix issues with rate-limiting (see https://github.com/ytdl-org/youtube-dl/issues/21729)
|
||||
property port : Int32 = 3000 # Port to listen for connections (overrided by command line argument)
|
||||
property host_binding : String = "0.0.0.0" # Host to bind (overrided by command line argument)
|
||||
property pool_size : Int32 = 100 # Pool size for HTTP requests to youtube.com and ytimg.com (each domain has a separate pool of `pool_size`)
|
||||
property use_quic : Bool = true # Use quic transport for youtube api
|
||||
|
||||
@[YAML::Field(converter: Preferences::StringToCookies)]
|
||||
property cookies : HTTP::Cookies = HTTP::Cookies.new # Saved cookies in "name1=value1; name2=value2..." format
|
||||
property captcha_key : String? = nil # Key for Anti-Captcha
|
||||
property captcha_api_url : String = "https://api.anti-captcha.com" # API URL for Anti-Captcha
|
||||
|
||||
def disabled?(option)
|
||||
case disabled = CONFIG.disable_proxy
|
||||
when Bool
|
||||
return disabled
|
||||
when Array
|
||||
if disabled.includes? option
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def self.load
|
||||
# Load config from file or YAML string env var
|
||||
env_config_file = "INVIDIOUS_CONFIG_FILE"
|
||||
env_config_yaml = "INVIDIOUS_CONFIG"
|
||||
|
||||
config_file = ENV.has_key?(env_config_file) ? ENV.fetch(env_config_file) : "config/config.yml"
|
||||
config_yaml = ENV.has_key?(env_config_yaml) ? ENV.fetch(env_config_yaml) : File.read(config_file)
|
||||
|
||||
config = Config.from_yaml(config_yaml)
|
||||
|
||||
# Update config from env vars (upcased and prefixed with "INVIDIOUS_")
|
||||
{% for ivar in Config.instance_vars %}
|
||||
{% env_id = "INVIDIOUS_#{ivar.id.upcase}" %}
|
||||
|
||||
if ENV.has_key?({{env_id}})
|
||||
# puts %(Config.{{ivar.id}} : Loading from env var {{env_id}})
|
||||
env_value = ENV.fetch({{env_id}})
|
||||
success = false
|
||||
|
||||
# Use YAML converter if specified
|
||||
{% ann = ivar.annotation(::YAML::Field) %}
|
||||
{% if ann && ann[:converter] %}
|
||||
puts %(Config.{{ivar.id}} : Parsing "#{env_value}" as {{ivar.type}} with {{ann[:converter]}} converter)
|
||||
config.{{ivar.id}} = {{ann[:converter]}}.from_yaml(YAML::ParseContext.new, YAML::Nodes.parse(ENV.fetch({{env_id}})).nodes[0])
|
||||
puts %(Config.{{ivar.id}} : Set to #{config.{{ivar.id}}})
|
||||
success = true
|
||||
|
||||
# Use regular YAML parser otherwise
|
||||
{% else %}
|
||||
{% ivar_types = ivar.type.union? ? ivar.type.union_types : [ivar.type] %}
|
||||
# Sort types to avoid parsing nulls and numbers as strings
|
||||
{% ivar_types = ivar_types.sort_by { |ivar_type| ivar_type == Nil ? 0 : ivar_type == Int32 ? 1 : 2 } %}
|
||||
{{ivar_types}}.each do |ivar_type|
|
||||
if !success
|
||||
begin
|
||||
# puts %(Config.{{ivar.id}} : Trying to parse "#{env_value}" as #{ivar_type})
|
||||
config.{{ivar.id}} = ivar_type.from_yaml(env_value)
|
||||
puts %(Config.{{ivar.id}} : Set to #{config.{{ivar.id}}} (#{ivar_type}))
|
||||
success = true
|
||||
rescue
|
||||
# nop
|
||||
end
|
||||
end
|
||||
end
|
||||
{% end %}
|
||||
|
||||
# Exit on fail
|
||||
if !success
|
||||
puts %(Config.{{ivar.id}} failed to parse #{env_value} as {{ivar.type}})
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
{% end %}
|
||||
|
||||
# Build database_url from db.* if it's not set directly
|
||||
if config.database_url.to_s.empty?
|
||||
if db = config.db
|
||||
config.database_url = URI.new(
|
||||
scheme: "postgres",
|
||||
user: db.user,
|
||||
password: db.password,
|
||||
host: db.host,
|
||||
port: db.port,
|
||||
path: db.dbname,
|
||||
)
|
||||
else
|
||||
puts "Config : Either database_url or db.* is required"
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
|
||||
return config
|
||||
end
|
||||
end
|
|
@ -22,193 +22,6 @@ struct Annotation
|
|||
property annotations : String
|
||||
end
|
||||
|
||||
struct ConfigPreferences
|
||||
include YAML::Serializable
|
||||
|
||||
property annotations : Bool = false
|
||||
property annotations_subscribed : Bool = false
|
||||
property autoplay : Bool = false
|
||||
property captions : Array(String) = ["", "", ""]
|
||||
property comments : Array(String) = ["youtube", ""]
|
||||
property continue : Bool = false
|
||||
property continue_autoplay : Bool = true
|
||||
property dark_mode : String = ""
|
||||
property latest_only : Bool = false
|
||||
property listen : Bool = false
|
||||
property local : Bool = false
|
||||
property locale : String = "en-US"
|
||||
property max_results : Int32 = 40
|
||||
property notifications_only : Bool = false
|
||||
property player_style : String = "invidious"
|
||||
property quality : String = "hd720"
|
||||
property quality_dash : String = "auto"
|
||||
property default_home : String? = "Popular"
|
||||
property feed_menu : Array(String) = ["Popular", "Trending", "Subscriptions", "Playlists"]
|
||||
property automatic_instance_redirect : Bool = false
|
||||
property related_videos : Bool = true
|
||||
property sort : String = "published"
|
||||
property speed : Float32 = 1.0_f32
|
||||
property thin_mode : Bool = false
|
||||
property unseen_only : Bool = false
|
||||
property video_loop : Bool = false
|
||||
property extend_desc : Bool = false
|
||||
property volume : Int32 = 100
|
||||
property vr_mode : Bool = true
|
||||
property show_nick : Bool = true
|
||||
|
||||
def to_tuple
|
||||
{% begin %}
|
||||
{
|
||||
{{*@type.instance_vars.map { |var| "#{var.name}: #{var.name}".id }}}
|
||||
}
|
||||
{% end %}
|
||||
end
|
||||
end
|
||||
|
||||
class Config
|
||||
include YAML::Serializable
|
||||
|
||||
property channel_threads : Int32 = 1 # Number of threads to use for crawling videos from channels (for updating subscriptions)
|
||||
property feed_threads : Int32 = 1 # Number of threads to use for updating feeds
|
||||
property output : String = "STDOUT" # Log file path or STDOUT
|
||||
property log_level : LogLevel = LogLevel::Info # Default log level, valid YAML values are ints and strings, see src/invidious/helpers/logger.cr
|
||||
property db : DBConfig? = nil # Database configuration with separate parameters (username, hostname, etc)
|
||||
|
||||
@[YAML::Field(converter: Preferences::URIConverter)]
|
||||
property database_url : URI = URI.parse("") # Database configuration using 12-Factor "Database URL" syntax
|
||||
property decrypt_polling : Bool = true # Use polling to keep decryption function up to date
|
||||
property full_refresh : Bool = false # Used for crawling channels: threads should check all videos uploaded by a channel
|
||||
property https_only : Bool? # Used to tell Invidious it is behind a proxy, so links to resources should be https://
|
||||
property hmac_key : String? # HMAC signing key for CSRF tokens and verifying pubsub subscriptions
|
||||
property domain : String? # Domain to be used for links to resources on the site where an absolute URL is required
|
||||
property use_pubsub_feeds : Bool | Int32 = false # Subscribe to channels using PubSubHubbub (requires domain, hmac_key)
|
||||
property popular_enabled : Bool = true
|
||||
property captcha_enabled : Bool = true
|
||||
property login_enabled : Bool = true
|
||||
property registration_enabled : Bool = true
|
||||
property statistics_enabled : Bool = false
|
||||
property admins : Array(String) = [] of String
|
||||
property external_port : Int32? = nil
|
||||
property default_user_preferences : ConfigPreferences = ConfigPreferences.from_yaml("")
|
||||
property dmca_content : Array(String) = [] of String # For compliance with DMCA, disables download widget using list of video IDs
|
||||
property check_tables : Bool = false # Check table integrity, automatically try to add any missing columns, create tables, etc.
|
||||
property cache_annotations : Bool = false # Cache annotations requested from IA, will not cache empty annotations or annotations that only contain cards
|
||||
property banner : String? = nil # Optional banner to be displayed along top of page for announcements, etc.
|
||||
property hsts : Bool? = true # Enables 'Strict-Transport-Security'. Ensure that `domain` and all subdomains are served securely
|
||||
property disable_proxy : Bool? | Array(String)? = false # Disable proxying server-wide: options: 'dash', 'livestreams', 'downloads', 'local'
|
||||
|
||||
@[YAML::Field(converter: Preferences::FamilyConverter)]
|
||||
property force_resolve : Socket::Family = Socket::Family::UNSPEC # Connect to YouTube over 'ipv6', 'ipv4'. Will sometimes resolve fix issues with rate-limiting (see https://github.com/ytdl-org/youtube-dl/issues/21729)
|
||||
property port : Int32 = 3000 # Port to listen for connections (overrided by command line argument)
|
||||
property host_binding : String = "0.0.0.0" # Host to bind (overrided by command line argument)
|
||||
property pool_size : Int32 = 100 # Pool size for HTTP requests to youtube.com and ytimg.com (each domain has a separate pool of `pool_size`)
|
||||
property use_quic : Bool = true # Use quic transport for youtube api
|
||||
|
||||
@[YAML::Field(converter: Preferences::StringToCookies)]
|
||||
property cookies : HTTP::Cookies = HTTP::Cookies.new # Saved cookies in "name1=value1; name2=value2..." format
|
||||
property captcha_key : String? = nil # Key for Anti-Captcha
|
||||
property captcha_api_url : String = "https://api.anti-captcha.com" # API URL for Anti-Captcha
|
||||
|
||||
def disabled?(option)
|
||||
case disabled = CONFIG.disable_proxy
|
||||
when Bool
|
||||
return disabled
|
||||
when Array
|
||||
if disabled.includes? option
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def self.load
|
||||
# Load config from file or YAML string env var
|
||||
env_config_file = "INVIDIOUS_CONFIG_FILE"
|
||||
env_config_yaml = "INVIDIOUS_CONFIG"
|
||||
|
||||
config_file = ENV.has_key?(env_config_file) ? ENV.fetch(env_config_file) : "config/config.yml"
|
||||
config_yaml = ENV.has_key?(env_config_yaml) ? ENV.fetch(env_config_yaml) : File.read(config_file)
|
||||
|
||||
config = Config.from_yaml(config_yaml)
|
||||
|
||||
# Update config from env vars (upcased and prefixed with "INVIDIOUS_")
|
||||
{% for ivar in Config.instance_vars %}
|
||||
{% env_id = "INVIDIOUS_#{ivar.id.upcase}" %}
|
||||
|
||||
if ENV.has_key?({{env_id}})
|
||||
# puts %(Config.{{ivar.id}} : Loading from env var {{env_id}})
|
||||
env_value = ENV.fetch({{env_id}})
|
||||
success = false
|
||||
|
||||
# Use YAML converter if specified
|
||||
{% ann = ivar.annotation(::YAML::Field) %}
|
||||
{% if ann && ann[:converter] %}
|
||||
puts %(Config.{{ivar.id}} : Parsing "#{env_value}" as {{ivar.type}} with {{ann[:converter]}} converter)
|
||||
config.{{ivar.id}} = {{ann[:converter]}}.from_yaml(YAML::ParseContext.new, YAML::Nodes.parse(ENV.fetch({{env_id}})).nodes[0])
|
||||
puts %(Config.{{ivar.id}} : Set to #{config.{{ivar.id}}})
|
||||
success = true
|
||||
|
||||
# Use regular YAML parser otherwise
|
||||
{% else %}
|
||||
{% ivar_types = ivar.type.union? ? ivar.type.union_types : [ivar.type] %}
|
||||
# Sort types to avoid parsing nulls and numbers as strings
|
||||
{% ivar_types = ivar_types.sort_by { |ivar_type| ivar_type == Nil ? 0 : ivar_type == Int32 ? 1 : 2 } %}
|
||||
{{ivar_types}}.each do |ivar_type|
|
||||
if !success
|
||||
begin
|
||||
# puts %(Config.{{ivar.id}} : Trying to parse "#{env_value}" as #{ivar_type})
|
||||
config.{{ivar.id}} = ivar_type.from_yaml(env_value)
|
||||
puts %(Config.{{ivar.id}} : Set to #{config.{{ivar.id}}} (#{ivar_type}))
|
||||
success = true
|
||||
rescue
|
||||
# nop
|
||||
end
|
||||
end
|
||||
end
|
||||
{% end %}
|
||||
|
||||
# Exit on fail
|
||||
if !success
|
||||
puts %(Config.{{ivar.id}} failed to parse #{env_value} as {{ivar.type}})
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
{% end %}
|
||||
|
||||
# Build database_url from db.* if it's not set directly
|
||||
if config.database_url.to_s.empty?
|
||||
if db = config.db
|
||||
config.database_url = URI.new(
|
||||
scheme: "postgres",
|
||||
user: db.user,
|
||||
password: db.password,
|
||||
host: db.host,
|
||||
port: db.port,
|
||||
path: db.dbname,
|
||||
)
|
||||
else
|
||||
puts "Config : Either database_url or db.* is required"
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
|
||||
return config
|
||||
end
|
||||
end
|
||||
|
||||
struct DBConfig
|
||||
include YAML::Serializable
|
||||
|
||||
property user : String
|
||||
property password : String
|
||||
property host : String
|
||||
property port : Int32
|
||||
property dbname : String
|
||||
end
|
||||
|
||||
def login_req(f_req)
|
||||
data = {
|
||||
# Unfortunately there's not much information available on `bgRequest`; part of Google's BotGuard
|
||||
|
|
456
src/invidious/user/preferences.cr
Normal file
456
src/invidious/user/preferences.cr
Normal file
|
@ -0,0 +1,456 @@
|
|||
#
|
||||
# This file contains the user preferences data structures and
|
||||
# all the associated validation/parsing routines.
|
||||
#
|
||||
|
||||
struct Preferences
|
||||
include JSON::Serializable
|
||||
include YAML::Serializable
|
||||
|
||||
property annotations : Bool = CONFIG.default_user_preferences.annotations
|
||||
property annotations_subscribed : Bool = CONFIG.default_user_preferences.annotations_subscribed
|
||||
property autoplay : Bool = CONFIG.default_user_preferences.autoplay
|
||||
property automatic_instance_redirect : Bool = CONFIG.default_user_preferences.automatic_instance_redirect
|
||||
|
||||
@[JSON::Field(converter: Preferences::StringToArray)]
|
||||
@[YAML::Field(converter: Preferences::StringToArray)]
|
||||
property captions : Array(String) = CONFIG.default_user_preferences.captions
|
||||
|
||||
@[JSON::Field(converter: Preferences::StringToArray)]
|
||||
@[YAML::Field(converter: Preferences::StringToArray)]
|
||||
property comments : Array(String) = CONFIG.default_user_preferences.comments
|
||||
property continue : Bool = CONFIG.default_user_preferences.continue
|
||||
property continue_autoplay : Bool = CONFIG.default_user_preferences.continue_autoplay
|
||||
|
||||
@[JSON::Field(converter: Preferences::BoolToString)]
|
||||
@[YAML::Field(converter: Preferences::BoolToString)]
|
||||
property dark_mode : String = CONFIG.default_user_preferences.dark_mode
|
||||
property latest_only : Bool = CONFIG.default_user_preferences.latest_only
|
||||
property listen : Bool = CONFIG.default_user_preferences.listen
|
||||
property local : Bool = CONFIG.default_user_preferences.local
|
||||
property vr_mode : Bool = CONFIG.default_user_preferences.vr_mode
|
||||
property show_nick : Bool = CONFIG.default_user_preferences.show_nick
|
||||
|
||||
@[JSON::Field(converter: Preferences::ProcessString)]
|
||||
property locale : String = CONFIG.default_user_preferences.locale
|
||||
|
||||
@[JSON::Field(converter: Preferences::ClampInt)]
|
||||
property max_results : Int32 = CONFIG.default_user_preferences.max_results
|
||||
property notifications_only : Bool = CONFIG.default_user_preferences.notifications_only
|
||||
|
||||
@[JSON::Field(converter: Preferences::ProcessString)]
|
||||
property player_style : String = CONFIG.default_user_preferences.player_style
|
||||
|
||||
@[JSON::Field(converter: Preferences::ProcessString)]
|
||||
property quality : String = CONFIG.default_user_preferences.quality
|
||||
@[JSON::Field(converter: Preferences::ProcessString)]
|
||||
property quality_dash : String = CONFIG.default_user_preferences.quality_dash
|
||||
property default_home : String? = CONFIG.default_user_preferences.default_home
|
||||
property feed_menu : Array(String) = CONFIG.default_user_preferences.feed_menu
|
||||
property related_videos : Bool = CONFIG.default_user_preferences.related_videos
|
||||
|
||||
@[JSON::Field(converter: Preferences::ProcessString)]
|
||||
property sort : String = CONFIG.default_user_preferences.sort
|
||||
property speed : Float32 = CONFIG.default_user_preferences.speed
|
||||
property thin_mode : Bool = CONFIG.default_user_preferences.thin_mode
|
||||
property unseen_only : Bool = CONFIG.default_user_preferences.unseen_only
|
||||
property video_loop : Bool = CONFIG.default_user_preferences.video_loop
|
||||
property extend_desc : Bool = CONFIG.default_user_preferences.extend_desc
|
||||
property volume : Int32 = CONFIG.default_user_preferences.volume
|
||||
|
||||
module BoolToString
|
||||
def self.to_json(value : String, json : JSON::Builder)
|
||||
json.string value
|
||||
end
|
||||
|
||||
def self.from_json(value : JSON::PullParser) : String
|
||||
begin
|
||||
result = value.read_string
|
||||
|
||||
if result.empty?
|
||||
CONFIG.default_user_preferences.dark_mode
|
||||
else
|
||||
result
|
||||
end
|
||||
rescue ex
|
||||
if value.read_bool
|
||||
"dark"
|
||||
else
|
||||
"light"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.to_yaml(value : String, yaml : YAML::Nodes::Builder)
|
||||
yaml.scalar value
|
||||
end
|
||||
|
||||
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : String
|
||||
unless node.is_a?(YAML::Nodes::Scalar)
|
||||
node.raise "Expected scalar, not #{node.class}"
|
||||
end
|
||||
|
||||
case node.value
|
||||
when "true"
|
||||
"dark"
|
||||
when "false"
|
||||
"light"
|
||||
when ""
|
||||
CONFIG.default_user_preferences.dark_mode
|
||||
else
|
||||
node.value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ClampInt
|
||||
def self.to_json(value : Int32, json : JSON::Builder)
|
||||
json.number value
|
||||
end
|
||||
|
||||
def self.from_json(value : JSON::PullParser) : Int32
|
||||
value.read_int.clamp(0, MAX_ITEMS_PER_PAGE).to_i32
|
||||
end
|
||||
|
||||
def self.to_yaml(value : Int32, yaml : YAML::Nodes::Builder)
|
||||
yaml.scalar value
|
||||
end
|
||||
|
||||
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : Int32
|
||||
node.value.clamp(0, MAX_ITEMS_PER_PAGE)
|
||||
end
|
||||
end
|
||||
|
||||
module FamilyConverter
|
||||
def self.to_yaml(value : Socket::Family, yaml : YAML::Nodes::Builder)
|
||||
case value
|
||||
when Socket::Family::UNSPEC
|
||||
yaml.scalar nil
|
||||
when Socket::Family::INET
|
||||
yaml.scalar "ipv4"
|
||||
when Socket::Family::INET6
|
||||
yaml.scalar "ipv6"
|
||||
when Socket::Family::UNIX
|
||||
raise "Invalid socket family #{value}"
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : Socket::Family
|
||||
if node.is_a?(YAML::Nodes::Scalar)
|
||||
case node.value.downcase
|
||||
when "ipv4"
|
||||
Socket::Family::INET
|
||||
when "ipv6"
|
||||
Socket::Family::INET6
|
||||
else
|
||||
Socket::Family::UNSPEC
|
||||
end
|
||||
else
|
||||
node.raise "Expected scalar, not #{node.class}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module URIConverter
|
||||
def self.to_yaml(value : URI, yaml : YAML::Nodes::Builder)
|
||||
yaml.scalar value.normalize!
|
||||
end
|
||||
|
||||
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : URI
|
||||
if node.is_a?(YAML::Nodes::Scalar)
|
||||
URI.parse node.value
|
||||
else
|
||||
node.raise "Expected scalar, not #{node.class}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ProcessString
|
||||
def self.to_json(value : String, json : JSON::Builder)
|
||||
json.string value
|
||||
end
|
||||
|
||||
def self.from_json(value : JSON::PullParser) : String
|
||||
HTML.escape(value.read_string[0, 100])
|
||||
end
|
||||
|
||||
def self.to_yaml(value : String, yaml : YAML::Nodes::Builder)
|
||||
yaml.scalar value
|
||||
end
|
||||
|
||||
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : String
|
||||
HTML.escape(node.value[0, 100])
|
||||
end
|
||||
end
|
||||
|
||||
module StringToArray
|
||||
def self.to_json(value : Array(String), json : JSON::Builder)
|
||||
json.array do
|
||||
value.each do |element|
|
||||
json.string element
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_json(value : JSON::PullParser) : Array(String)
|
||||
begin
|
||||
result = [] of String
|
||||
value.read_array do
|
||||
result << HTML.escape(value.read_string[0, 100])
|
||||
end
|
||||
rescue ex
|
||||
result = [HTML.escape(value.read_string[0, 100]), ""]
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
def self.to_yaml(value : Array(String), yaml : YAML::Nodes::Builder)
|
||||
yaml.sequence do
|
||||
value.each do |element|
|
||||
yaml.scalar element
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : Array(String)
|
||||
begin
|
||||
unless node.is_a?(YAML::Nodes::Sequence)
|
||||
node.raise "Expected sequence, not #{node.class}"
|
||||
end
|
||||
|
||||
result = [] of String
|
||||
node.nodes.each do |item|
|
||||
unless item.is_a?(YAML::Nodes::Scalar)
|
||||
node.raise "Expected scalar, not #{item.class}"
|
||||
end
|
||||
|
||||
result << HTML.escape(item.value[0, 100])
|
||||
end
|
||||
rescue ex
|
||||
if node.is_a?(YAML::Nodes::Scalar)
|
||||
result = [HTML.escape(node.value[0, 100]), ""]
|
||||
else
|
||||
result = ["", ""]
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
module StringToCookies
|
||||
def self.to_yaml(value : HTTP::Cookies, yaml : YAML::Nodes::Builder)
|
||||
(value.map { |c| "#{c.name}=#{c.value}" }).join("; ").to_yaml(yaml)
|
||||
end
|
||||
|
||||
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : HTTP::Cookies
|
||||
unless node.is_a?(YAML::Nodes::Scalar)
|
||||
node.raise "Expected scalar, not #{node.class}"
|
||||
end
|
||||
|
||||
cookies = HTTP::Cookies.new
|
||||
node.value.split(";").each do |cookie|
|
||||
next if cookie.strip.empty?
|
||||
name, value = cookie.split("=", 2)
|
||||
cookies << HTTP::Cookie.new(name.strip, value.strip)
|
||||
end
|
||||
|
||||
cookies
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
struct ConfigPreferences
|
||||
include YAML::Serializable
|
||||
|
||||
property annotations : Bool = false
|
||||
property annotations_subscribed : Bool = false
|
||||
property autoplay : Bool = false
|
||||
property captions : Array(String) = ["", "", ""]
|
||||
property comments : Array(String) = ["youtube", ""]
|
||||
property continue : Bool = false
|
||||
property continue_autoplay : Bool = true
|
||||
property dark_mode : String = ""
|
||||
property latest_only : Bool = false
|
||||
property listen : Bool = false
|
||||
property local : Bool = false
|
||||
property locale : String = "en-US"
|
||||
property max_results : Int32 = 40
|
||||
property notifications_only : Bool = false
|
||||
property player_style : String = "invidious"
|
||||
property quality : String = "hd720"
|
||||
property quality_dash : String = "auto"
|
||||
property default_home : String? = "Popular"
|
||||
property feed_menu : Array(String) = ["Popular", "Trending", "Subscriptions", "Playlists"]
|
||||
property automatic_instance_redirect : Bool = false
|
||||
property related_videos : Bool = true
|
||||
property sort : String = "published"
|
||||
property speed : Float32 = 1.0_f32
|
||||
property thin_mode : Bool = false
|
||||
property unseen_only : Bool = false
|
||||
property video_loop : Bool = false
|
||||
property extend_desc : Bool = false
|
||||
property volume : Int32 = 100
|
||||
property vr_mode : Bool = true
|
||||
property show_nick : Bool = true
|
||||
|
||||
def to_tuple
|
||||
{% begin %}
|
||||
{
|
||||
{{*@type.instance_vars.map { |var| "#{var.name}: #{var.name}".id }}}
|
||||
}
|
||||
{% end %}
|
||||
end
|
||||
end
|
||||
|
||||
struct VideoPreferences
|
||||
include JSON::Serializable
|
||||
|
||||
property annotations : Bool
|
||||
property autoplay : Bool
|
||||
property comments : Array(String)
|
||||
property continue : Bool
|
||||
property continue_autoplay : Bool
|
||||
property controls : Bool
|
||||
property listen : Bool
|
||||
property local : Bool
|
||||
property preferred_captions : Array(String)
|
||||
property player_style : String
|
||||
property quality : String
|
||||
property quality_dash : String
|
||||
property raw : Bool
|
||||
property region : String?
|
||||
property related_videos : Bool
|
||||
property speed : Float32 | Float64
|
||||
property video_end : Float64 | Int32
|
||||
property video_loop : Bool
|
||||
property extend_desc : Bool
|
||||
property video_start : Float64 | Int32
|
||||
property volume : Int32
|
||||
property vr_mode : Bool
|
||||
end
|
||||
|
||||
def process_video_params(query, preferences)
|
||||
annotations = query["iv_load_policy"]?.try &.to_i?
|
||||
autoplay = query["autoplay"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
comments = query["comments"]?.try &.split(",").map { |a| a.downcase }
|
||||
continue = query["continue"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
continue_autoplay = query["continue_autoplay"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
listen = query["listen"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
local = query["local"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
player_style = query["player_style"]?
|
||||
preferred_captions = query["subtitles"]?.try &.split(",").map { |a| a.downcase }
|
||||
quality = query["quality"]?
|
||||
quality_dash = query["quality_dash"]?
|
||||
region = query["region"]?
|
||||
related_videos = query["related_videos"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
speed = query["speed"]?.try &.rchop("x").to_f?
|
||||
video_loop = query["loop"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
extend_desc = query["extend_desc"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
volume = query["volume"]?.try &.to_i?
|
||||
vr_mode = query["vr_mode"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
|
||||
if preferences
|
||||
# region ||= preferences.region
|
||||
annotations ||= preferences.annotations.to_unsafe
|
||||
autoplay ||= preferences.autoplay.to_unsafe
|
||||
comments ||= preferences.comments
|
||||
continue ||= preferences.continue.to_unsafe
|
||||
continue_autoplay ||= preferences.continue_autoplay.to_unsafe
|
||||
listen ||= preferences.listen.to_unsafe
|
||||
local ||= preferences.local.to_unsafe
|
||||
player_style ||= preferences.player_style
|
||||
preferred_captions ||= preferences.captions
|
||||
quality ||= preferences.quality
|
||||
quality_dash ||= preferences.quality_dash
|
||||
related_videos ||= preferences.related_videos.to_unsafe
|
||||
speed ||= preferences.speed
|
||||
video_loop ||= preferences.video_loop.to_unsafe
|
||||
extend_desc ||= preferences.extend_desc.to_unsafe
|
||||
volume ||= preferences.volume
|
||||
vr_mode ||= preferences.vr_mode.to_unsafe
|
||||
end
|
||||
|
||||
annotations ||= CONFIG.default_user_preferences.annotations.to_unsafe
|
||||
autoplay ||= CONFIG.default_user_preferences.autoplay.to_unsafe
|
||||
comments ||= CONFIG.default_user_preferences.comments
|
||||
continue ||= CONFIG.default_user_preferences.continue.to_unsafe
|
||||
continue_autoplay ||= CONFIG.default_user_preferences.continue_autoplay.to_unsafe
|
||||
listen ||= CONFIG.default_user_preferences.listen.to_unsafe
|
||||
local ||= CONFIG.default_user_preferences.local.to_unsafe
|
||||
player_style ||= CONFIG.default_user_preferences.player_style
|
||||
preferred_captions ||= CONFIG.default_user_preferences.captions
|
||||
quality ||= CONFIG.default_user_preferences.quality
|
||||
quality_dash ||= CONFIG.default_user_preferences.quality_dash
|
||||
related_videos ||= CONFIG.default_user_preferences.related_videos.to_unsafe
|
||||
speed ||= CONFIG.default_user_preferences.speed
|
||||
video_loop ||= CONFIG.default_user_preferences.video_loop.to_unsafe
|
||||
extend_desc ||= CONFIG.default_user_preferences.extend_desc.to_unsafe
|
||||
volume ||= CONFIG.default_user_preferences.volume
|
||||
vr_mode ||= CONFIG.default_user_preferences.vr_mode.to_unsafe
|
||||
|
||||
annotations = annotations == 1
|
||||
autoplay = autoplay == 1
|
||||
continue = continue == 1
|
||||
continue_autoplay = continue_autoplay == 1
|
||||
listen = listen == 1
|
||||
local = local == 1
|
||||
related_videos = related_videos == 1
|
||||
video_loop = video_loop == 1
|
||||
extend_desc = extend_desc == 1
|
||||
vr_mode = vr_mode == 1
|
||||
|
||||
if CONFIG.disabled?("dash") && quality == "dash"
|
||||
quality = "high"
|
||||
end
|
||||
|
||||
if CONFIG.disabled?("local") && local
|
||||
local = false
|
||||
end
|
||||
|
||||
if start = query["t"]? || query["time_continue"]? || query["start"]?
|
||||
video_start = decode_time(start)
|
||||
end
|
||||
video_start ||= 0
|
||||
|
||||
if query["end"]?
|
||||
video_end = decode_time(query["end"])
|
||||
end
|
||||
video_end ||= -1
|
||||
|
||||
raw = query["raw"]?.try &.to_i?
|
||||
raw ||= 0
|
||||
raw = raw == 1
|
||||
|
||||
controls = query["controls"]?.try &.to_i?
|
||||
controls ||= 1
|
||||
controls = controls >= 1
|
||||
|
||||
params = VideoPreferences.new({
|
||||
annotations: annotations,
|
||||
autoplay: autoplay,
|
||||
comments: comments,
|
||||
continue: continue,
|
||||
continue_autoplay: continue_autoplay,
|
||||
controls: controls,
|
||||
listen: listen,
|
||||
local: local,
|
||||
player_style: player_style,
|
||||
preferred_captions: preferred_captions,
|
||||
quality: quality,
|
||||
quality_dash: quality_dash,
|
||||
raw: raw,
|
||||
region: region,
|
||||
related_videos: related_videos,
|
||||
speed: speed,
|
||||
video_end: video_end,
|
||||
video_loop: video_loop,
|
||||
extend_desc: extend_desc,
|
||||
video_start: video_start,
|
||||
volume: volume,
|
||||
vr_mode: vr_mode,
|
||||
})
|
||||
|
||||
return params
|
||||
end
|
|
@ -29,264 +29,6 @@ struct User
|
|||
end
|
||||
end
|
||||
|
||||
struct Preferences
|
||||
include JSON::Serializable
|
||||
include YAML::Serializable
|
||||
|
||||
property annotations : Bool = CONFIG.default_user_preferences.annotations
|
||||
property annotations_subscribed : Bool = CONFIG.default_user_preferences.annotations_subscribed
|
||||
property autoplay : Bool = CONFIG.default_user_preferences.autoplay
|
||||
property automatic_instance_redirect : Bool = CONFIG.default_user_preferences.automatic_instance_redirect
|
||||
|
||||
@[JSON::Field(converter: Preferences::StringToArray)]
|
||||
@[YAML::Field(converter: Preferences::StringToArray)]
|
||||
property captions : Array(String) = CONFIG.default_user_preferences.captions
|
||||
|
||||
@[JSON::Field(converter: Preferences::StringToArray)]
|
||||
@[YAML::Field(converter: Preferences::StringToArray)]
|
||||
property comments : Array(String) = CONFIG.default_user_preferences.comments
|
||||
property continue : Bool = CONFIG.default_user_preferences.continue
|
||||
property continue_autoplay : Bool = CONFIG.default_user_preferences.continue_autoplay
|
||||
|
||||
@[JSON::Field(converter: Preferences::BoolToString)]
|
||||
@[YAML::Field(converter: Preferences::BoolToString)]
|
||||
property dark_mode : String = CONFIG.default_user_preferences.dark_mode
|
||||
property latest_only : Bool = CONFIG.default_user_preferences.latest_only
|
||||
property listen : Bool = CONFIG.default_user_preferences.listen
|
||||
property local : Bool = CONFIG.default_user_preferences.local
|
||||
property vr_mode : Bool = CONFIG.default_user_preferences.vr_mode
|
||||
property show_nick : Bool = CONFIG.default_user_preferences.show_nick
|
||||
|
||||
@[JSON::Field(converter: Preferences::ProcessString)]
|
||||
property locale : String = CONFIG.default_user_preferences.locale
|
||||
|
||||
@[JSON::Field(converter: Preferences::ClampInt)]
|
||||
property max_results : Int32 = CONFIG.default_user_preferences.max_results
|
||||
property notifications_only : Bool = CONFIG.default_user_preferences.notifications_only
|
||||
|
||||
@[JSON::Field(converter: Preferences::ProcessString)]
|
||||
property player_style : String = CONFIG.default_user_preferences.player_style
|
||||
|
||||
@[JSON::Field(converter: Preferences::ProcessString)]
|
||||
property quality : String = CONFIG.default_user_preferences.quality
|
||||
@[JSON::Field(converter: Preferences::ProcessString)]
|
||||
property quality_dash : String = CONFIG.default_user_preferences.quality_dash
|
||||
property default_home : String? = CONFIG.default_user_preferences.default_home
|
||||
property feed_menu : Array(String) = CONFIG.default_user_preferences.feed_menu
|
||||
property related_videos : Bool = CONFIG.default_user_preferences.related_videos
|
||||
|
||||
@[JSON::Field(converter: Preferences::ProcessString)]
|
||||
property sort : String = CONFIG.default_user_preferences.sort
|
||||
property speed : Float32 = CONFIG.default_user_preferences.speed
|
||||
property thin_mode : Bool = CONFIG.default_user_preferences.thin_mode
|
||||
property unseen_only : Bool = CONFIG.default_user_preferences.unseen_only
|
||||
property video_loop : Bool = CONFIG.default_user_preferences.video_loop
|
||||
property extend_desc : Bool = CONFIG.default_user_preferences.extend_desc
|
||||
property volume : Int32 = CONFIG.default_user_preferences.volume
|
||||
|
||||
module BoolToString
|
||||
def self.to_json(value : String, json : JSON::Builder)
|
||||
json.string value
|
||||
end
|
||||
|
||||
def self.from_json(value : JSON::PullParser) : String
|
||||
begin
|
||||
result = value.read_string
|
||||
|
||||
if result.empty?
|
||||
CONFIG.default_user_preferences.dark_mode
|
||||
else
|
||||
result
|
||||
end
|
||||
rescue ex
|
||||
if value.read_bool
|
||||
"dark"
|
||||
else
|
||||
"light"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.to_yaml(value : String, yaml : YAML::Nodes::Builder)
|
||||
yaml.scalar value
|
||||
end
|
||||
|
||||
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : String
|
||||
unless node.is_a?(YAML::Nodes::Scalar)
|
||||
node.raise "Expected scalar, not #{node.class}"
|
||||
end
|
||||
|
||||
case node.value
|
||||
when "true"
|
||||
"dark"
|
||||
when "false"
|
||||
"light"
|
||||
when ""
|
||||
CONFIG.default_user_preferences.dark_mode
|
||||
else
|
||||
node.value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ClampInt
|
||||
def self.to_json(value : Int32, json : JSON::Builder)
|
||||
json.number value
|
||||
end
|
||||
|
||||
def self.from_json(value : JSON::PullParser) : Int32
|
||||
value.read_int.clamp(0, MAX_ITEMS_PER_PAGE).to_i32
|
||||
end
|
||||
|
||||
def self.to_yaml(value : Int32, yaml : YAML::Nodes::Builder)
|
||||
yaml.scalar value
|
||||
end
|
||||
|
||||
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : Int32
|
||||
node.value.clamp(0, MAX_ITEMS_PER_PAGE)
|
||||
end
|
||||
end
|
||||
|
||||
module FamilyConverter
|
||||
def self.to_yaml(value : Socket::Family, yaml : YAML::Nodes::Builder)
|
||||
case value
|
||||
when Socket::Family::UNSPEC
|
||||
yaml.scalar nil
|
||||
when Socket::Family::INET
|
||||
yaml.scalar "ipv4"
|
||||
when Socket::Family::INET6
|
||||
yaml.scalar "ipv6"
|
||||
when Socket::Family::UNIX
|
||||
raise "Invalid socket family #{value}"
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : Socket::Family
|
||||
if node.is_a?(YAML::Nodes::Scalar)
|
||||
case node.value.downcase
|
||||
when "ipv4"
|
||||
Socket::Family::INET
|
||||
when "ipv6"
|
||||
Socket::Family::INET6
|
||||
else
|
||||
Socket::Family::UNSPEC
|
||||
end
|
||||
else
|
||||
node.raise "Expected scalar, not #{node.class}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module URIConverter
|
||||
def self.to_yaml(value : URI, yaml : YAML::Nodes::Builder)
|
||||
yaml.scalar value.normalize!
|
||||
end
|
||||
|
||||
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : URI
|
||||
if node.is_a?(YAML::Nodes::Scalar)
|
||||
URI.parse node.value
|
||||
else
|
||||
node.raise "Expected scalar, not #{node.class}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module ProcessString
|
||||
def self.to_json(value : String, json : JSON::Builder)
|
||||
json.string value
|
||||
end
|
||||
|
||||
def self.from_json(value : JSON::PullParser) : String
|
||||
HTML.escape(value.read_string[0, 100])
|
||||
end
|
||||
|
||||
def self.to_yaml(value : String, yaml : YAML::Nodes::Builder)
|
||||
yaml.scalar value
|
||||
end
|
||||
|
||||
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : String
|
||||
HTML.escape(node.value[0, 100])
|
||||
end
|
||||
end
|
||||
|
||||
module StringToArray
|
||||
def self.to_json(value : Array(String), json : JSON::Builder)
|
||||
json.array do
|
||||
value.each do |element|
|
||||
json.string element
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_json(value : JSON::PullParser) : Array(String)
|
||||
begin
|
||||
result = [] of String
|
||||
value.read_array do
|
||||
result << HTML.escape(value.read_string[0, 100])
|
||||
end
|
||||
rescue ex
|
||||
result = [HTML.escape(value.read_string[0, 100]), ""]
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
def self.to_yaml(value : Array(String), yaml : YAML::Nodes::Builder)
|
||||
yaml.sequence do
|
||||
value.each do |element|
|
||||
yaml.scalar element
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : Array(String)
|
||||
begin
|
||||
unless node.is_a?(YAML::Nodes::Sequence)
|
||||
node.raise "Expected sequence, not #{node.class}"
|
||||
end
|
||||
|
||||
result = [] of String
|
||||
node.nodes.each do |item|
|
||||
unless item.is_a?(YAML::Nodes::Scalar)
|
||||
node.raise "Expected scalar, not #{item.class}"
|
||||
end
|
||||
|
||||
result << HTML.escape(item.value[0, 100])
|
||||
end
|
||||
rescue ex
|
||||
if node.is_a?(YAML::Nodes::Scalar)
|
||||
result = [HTML.escape(node.value[0, 100]), ""]
|
||||
else
|
||||
result = ["", ""]
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
module StringToCookies
|
||||
def self.to_yaml(value : HTTP::Cookies, yaml : YAML::Nodes::Builder)
|
||||
(value.map { |c| "#{c.name}=#{c.value}" }).join("; ").to_yaml(yaml)
|
||||
end
|
||||
|
||||
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : HTTP::Cookies
|
||||
unless node.is_a?(YAML::Nodes::Scalar)
|
||||
node.raise "Expected scalar, not #{node.class}"
|
||||
end
|
||||
|
||||
cookies = HTTP::Cookies.new
|
||||
node.value.split(";").each do |cookie|
|
||||
next if cookie.strip.empty?
|
||||
name, value = cookie.split("=", 2)
|
||||
cookies << HTTP::Cookie.new(name.strip, value.strip)
|
||||
end
|
||||
|
||||
cookies
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_user(sid, headers, db, refresh = true)
|
||||
if email = db.query_one?("SELECT email FROM session_ids WHERE id = $1", sid, as: String)
|
||||
user = db.query_one("SELECT * FROM users WHERE email = $1", email, as: User)
|
||||
|
|
|
@ -221,33 +221,6 @@ VIDEO_FORMATS = {
|
|||
"397" => {"ext" => "mp4", "height" => 480, "vcodec" => "av01.0.05M.08"},
|
||||
}
|
||||
|
||||
struct VideoPreferences
|
||||
include JSON::Serializable
|
||||
|
||||
property annotations : Bool
|
||||
property autoplay : Bool
|
||||
property comments : Array(String)
|
||||
property continue : Bool
|
||||
property continue_autoplay : Bool
|
||||
property controls : Bool
|
||||
property listen : Bool
|
||||
property local : Bool
|
||||
property preferred_captions : Array(String)
|
||||
property player_style : String
|
||||
property quality : String
|
||||
property quality_dash : String
|
||||
property raw : Bool
|
||||
property region : String?
|
||||
property related_videos : Bool
|
||||
property speed : Float32 | Float64
|
||||
property video_end : Float64 | Int32
|
||||
property video_loop : Bool
|
||||
property extend_desc : Bool
|
||||
property video_start : Float64 | Int32
|
||||
property volume : Int32
|
||||
property vr_mode : Bool
|
||||
end
|
||||
|
||||
struct Video
|
||||
include DB::Serializable
|
||||
|
||||
|
@ -1069,130 +1042,6 @@ def process_continuation(db, query, plid, id)
|
|||
continuation
|
||||
end
|
||||
|
||||
def process_video_params(query, preferences)
|
||||
annotations = query["iv_load_policy"]?.try &.to_i?
|
||||
autoplay = query["autoplay"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
comments = query["comments"]?.try &.split(",").map { |a| a.downcase }
|
||||
continue = query["continue"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
continue_autoplay = query["continue_autoplay"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
listen = query["listen"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
local = query["local"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
player_style = query["player_style"]?
|
||||
preferred_captions = query["subtitles"]?.try &.split(",").map { |a| a.downcase }
|
||||
quality = query["quality"]?
|
||||
quality_dash = query["quality_dash"]?
|
||||
region = query["region"]?
|
||||
related_videos = query["related_videos"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
speed = query["speed"]?.try &.rchop("x").to_f?
|
||||
video_loop = query["loop"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
extend_desc = query["extend_desc"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
volume = query["volume"]?.try &.to_i?
|
||||
vr_mode = query["vr_mode"]?.try { |q| (q == "true" || q == "1").to_unsafe }
|
||||
|
||||
if preferences
|
||||
# region ||= preferences.region
|
||||
annotations ||= preferences.annotations.to_unsafe
|
||||
autoplay ||= preferences.autoplay.to_unsafe
|
||||
comments ||= preferences.comments
|
||||
continue ||= preferences.continue.to_unsafe
|
||||
continue_autoplay ||= preferences.continue_autoplay.to_unsafe
|
||||
listen ||= preferences.listen.to_unsafe
|
||||
local ||= preferences.local.to_unsafe
|
||||
player_style ||= preferences.player_style
|
||||
preferred_captions ||= preferences.captions
|
||||
quality ||= preferences.quality
|
||||
quality_dash ||= preferences.quality_dash
|
||||
related_videos ||= preferences.related_videos.to_unsafe
|
||||
speed ||= preferences.speed
|
||||
video_loop ||= preferences.video_loop.to_unsafe
|
||||
extend_desc ||= preferences.extend_desc.to_unsafe
|
||||
volume ||= preferences.volume
|
||||
vr_mode ||= preferences.vr_mode.to_unsafe
|
||||
end
|
||||
|
||||
annotations ||= CONFIG.default_user_preferences.annotations.to_unsafe
|
||||
autoplay ||= CONFIG.default_user_preferences.autoplay.to_unsafe
|
||||
comments ||= CONFIG.default_user_preferences.comments
|
||||
continue ||= CONFIG.default_user_preferences.continue.to_unsafe
|
||||
continue_autoplay ||= CONFIG.default_user_preferences.continue_autoplay.to_unsafe
|
||||
listen ||= CONFIG.default_user_preferences.listen.to_unsafe
|
||||
local ||= CONFIG.default_user_preferences.local.to_unsafe
|
||||
player_style ||= CONFIG.default_user_preferences.player_style
|
||||
preferred_captions ||= CONFIG.default_user_preferences.captions
|
||||
quality ||= CONFIG.default_user_preferences.quality
|
||||
quality_dash ||= CONFIG.default_user_preferences.quality_dash
|
||||
related_videos ||= CONFIG.default_user_preferences.related_videos.to_unsafe
|
||||
speed ||= CONFIG.default_user_preferences.speed
|
||||
video_loop ||= CONFIG.default_user_preferences.video_loop.to_unsafe
|
||||
extend_desc ||= CONFIG.default_user_preferences.extend_desc.to_unsafe
|
||||
volume ||= CONFIG.default_user_preferences.volume
|
||||
vr_mode ||= CONFIG.default_user_preferences.vr_mode.to_unsafe
|
||||
|
||||
annotations = annotations == 1
|
||||
autoplay = autoplay == 1
|
||||
continue = continue == 1
|
||||
continue_autoplay = continue_autoplay == 1
|
||||
listen = listen == 1
|
||||
local = local == 1
|
||||
related_videos = related_videos == 1
|
||||
video_loop = video_loop == 1
|
||||
extend_desc = extend_desc == 1
|
||||
vr_mode = vr_mode == 1
|
||||
|
||||
if CONFIG.disabled?("dash") && quality == "dash"
|
||||
quality = "high"
|
||||
end
|
||||
|
||||
if CONFIG.disabled?("local") && local
|
||||
local = false
|
||||
end
|
||||
|
||||
if start = query["t"]? || query["time_continue"]? || query["start"]?
|
||||
video_start = decode_time(start)
|
||||
end
|
||||
video_start ||= 0
|
||||
|
||||
if query["end"]?
|
||||
video_end = decode_time(query["end"])
|
||||
end
|
||||
video_end ||= -1
|
||||
|
||||
raw = query["raw"]?.try &.to_i?
|
||||
raw ||= 0
|
||||
raw = raw == 1
|
||||
|
||||
controls = query["controls"]?.try &.to_i?
|
||||
controls ||= 1
|
||||
controls = controls >= 1
|
||||
|
||||
params = VideoPreferences.new({
|
||||
annotations: annotations,
|
||||
autoplay: autoplay,
|
||||
comments: comments,
|
||||
continue: continue,
|
||||
continue_autoplay: continue_autoplay,
|
||||
controls: controls,
|
||||
listen: listen,
|
||||
local: local,
|
||||
player_style: player_style,
|
||||
preferred_captions: preferred_captions,
|
||||
quality: quality,
|
||||
quality_dash: quality_dash,
|
||||
raw: raw,
|
||||
region: region,
|
||||
related_videos: related_videos,
|
||||
speed: speed,
|
||||
video_end: video_end,
|
||||
video_loop: video_loop,
|
||||
extend_desc: extend_desc,
|
||||
video_start: video_start,
|
||||
volume: volume,
|
||||
vr_mode: vr_mode,
|
||||
})
|
||||
|
||||
return params
|
||||
end
|
||||
|
||||
def build_thumbnails(id)
|
||||
return {
|
||||
{host: HOST_URL, height: 720, width: 1280, name: "maxres", url: "maxres"},
|
||||
|
|
Loading…
Reference in a new issue