mirror of
https://github.com/iv-org/invidious.git
synced 2026-10-24 13:59:14 -05:00
chore: update to ameba 1.7.0 and adapt most of the code to it (#6082)
* chore: update to ameba 1.7.0 and adapt most of the code to it * forgot to add this to build ameba into the ./bin directory for use, as ameba does not longer offer a postinstall script * forgot to update ameba in the shards files * remove leftover : in rescue * Use ameba linter action instead of installing it with shards
This commit is contained in:
parent
7286c6dea4
commit
907fe54aab
31
.ameba.yml
31
.ameba.yml
@ -5,20 +5,26 @@
|
|||||||
# Exclude assigns for ECR files
|
# Exclude assigns for ECR files
|
||||||
Lint/UselessAssign:
|
Lint/UselessAssign:
|
||||||
Excluded:
|
Excluded:
|
||||||
- src/invidious.cr
|
- src/invidious.cr
|
||||||
- src/invidious/helpers/errors.cr
|
- src/invidious/helpers/errors.cr
|
||||||
- src/invidious/routes/*.cr
|
- src/invidious/routes/*.cr
|
||||||
|
- src/invidious/views/**/**
|
||||||
|
|
||||||
|
# Exclude unused arguments for ECR files
|
||||||
|
Lint/UnusedArgument:
|
||||||
|
Excluded:
|
||||||
|
- src/invidious/views/**/**
|
||||||
|
|
||||||
# Ignore false negative (if !db.query_one?...)
|
# Ignore false negative (if !db.query_one?...)
|
||||||
Lint/UnreachableCode:
|
Lint/UnreachableCode:
|
||||||
Excluded:
|
Excluded:
|
||||||
- src/invidious/database/base.cr
|
- src/invidious/database/base.cr
|
||||||
|
|
||||||
# Ignore shadowed variable `key` (it works for now, and that's
|
# Ignore shadowed variable `key` (it works for now, and that's
|
||||||
# a sensitive part of the code)
|
# a sensitive part of the code)
|
||||||
Lint/ShadowingOuterLocalVar:
|
Lint/ShadowingOuterLocalVar:
|
||||||
Excluded:
|
Excluded:
|
||||||
- src/invidious/helpers/tokens.cr
|
- src/invidious/helpers/tokens.cr
|
||||||
|
|
||||||
Lint/NotNil:
|
Lint/NotNil:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
@ -27,7 +33,6 @@ Lint/SpecFilename:
|
|||||||
Excluded:
|
Excluded:
|
||||||
- spec/parsers_helper.cr
|
- spec/parsers_helper.cr
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Style
|
# Style
|
||||||
#
|
#
|
||||||
@ -44,6 +49,15 @@ Style/RedundantNext:
|
|||||||
Style/ParenthesesAroundCondition:
|
Style/ParenthesesAroundCondition:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
# Disable this as it's really useful for functions and variables
|
||||||
|
# that belong to a same module, struct or class, and it can be confused
|
||||||
|
# by a global function.
|
||||||
|
# This is subject to change with https://github.com/iv-org/invidious/pull/6046
|
||||||
|
# where there will not be more global variables or functions, well, that's
|
||||||
|
# the goal.
|
||||||
|
Style/RedundantSelf:
|
||||||
|
Enabled: false
|
||||||
|
|
||||||
# This requires a rewrite of most data structs (and their usage) in Invidious.
|
# This requires a rewrite of most data structs (and their usage) in Invidious.
|
||||||
Naming/QueryBoolMethods:
|
Naming/QueryBoolMethods:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
@ -56,12 +70,11 @@ Naming/BlockParameterName:
|
|||||||
|
|
||||||
# Hides TODO comment warnings.
|
# Hides TODO comment warnings.
|
||||||
#
|
#
|
||||||
# Call `bin/ameba --only Documentation/DocumentationAdmonition` to
|
# Call `bin/ameba --only Documentation/Admonition` to
|
||||||
# list them
|
# list them
|
||||||
Documentation/DocumentationAdmonition:
|
Documentation/Admonition:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Metrics
|
# Metrics
|
||||||
#
|
#
|
||||||
|
|||||||
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@ -146,7 +146,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
./lib
|
./lib
|
||||||
./bin
|
|
||||||
key: shards-${{ hashFiles('shard.lock') }}-${{ steps.lint_step_install_crystal.outputs.crystal }}
|
key: shards-${{ hashFiles('shard.lock') }}-${{ steps.lint_step_install_crystal.outputs.crystal }}
|
||||||
|
|
||||||
- name: Install Shards
|
- name: Install Shards
|
||||||
@ -164,4 +163,4 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Run Ameba linter
|
- name: Run Ameba linter
|
||||||
run: bin/ameba
|
uses: crystal-ameba/github-action@v1
|
||||||
|
|||||||
@ -2,7 +2,7 @@ version: 2.0
|
|||||||
shards:
|
shards:
|
||||||
ameba:
|
ameba:
|
||||||
git: https://github.com/crystal-ameba/ameba.git
|
git: https://github.com/crystal-ameba/ameba.git
|
||||||
version: 1.6.4
|
version: 1.7.0
|
||||||
|
|
||||||
athena-negotiation:
|
athena-negotiation:
|
||||||
git: https://github.com/athena-framework/negotiation.git
|
git: https://github.com/athena-framework/negotiation.git
|
||||||
|
|||||||
@ -8,6 +8,8 @@ authors:
|
|||||||
targets:
|
targets:
|
||||||
invidious:
|
invidious:
|
||||||
main: src/invidious.cr
|
main: src/invidious.cr
|
||||||
|
ameba:
|
||||||
|
main: lib/ameba/bin/ameba.cr
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Invidious is an alternative front-end to YouTube
|
Invidious is an alternative front-end to YouTube
|
||||||
@ -38,7 +40,7 @@ development_dependencies:
|
|||||||
version: ~> 0.12.4
|
version: ~> 0.12.4
|
||||||
ameba:
|
ameba:
|
||||||
github: crystal-ameba/ameba
|
github: crystal-ameba/ameba
|
||||||
version: ~> 1.6.4
|
version: ~> 1.7.0
|
||||||
|
|
||||||
crystal: ">= 1.14.1, < 2.0.0"
|
crystal: ">= 1.14.1, < 2.0.0"
|
||||||
|
|
||||||
|
|||||||
@ -59,7 +59,7 @@ end
|
|||||||
|
|
||||||
# Get relative file path to a file within the static_assets_handler folder
|
# Get relative file path to a file within the static_assets_handler folder
|
||||||
macro get_file_path(basename)
|
macro get_file_path(basename)
|
||||||
"spec/http_server/handlers/static_assets_handler/#{ {{basename}} }"
|
"spec/http_server/handlers/static_assets_handler/#{ {{ basename }} }"
|
||||||
end
|
end
|
||||||
|
|
||||||
Spectator.describe StaticAssetsHandler do
|
Spectator.describe StaticAssetsHandler do
|
||||||
|
|||||||
@ -8,21 +8,21 @@ end
|
|||||||
|
|
||||||
def csv_sample
|
def csv_sample
|
||||||
return <<-CSV
|
return <<-CSV
|
||||||
Kanal-ID,Kanal-URL,Kanaltitel
|
Kanal-ID,Kanal-URL,Kanaltitel
|
||||||
UC0hHW5Y08ggq-9kbrGgWj0A,http://www.youtube.com/channel/UC0hHW5Y08ggq-9kbrGgWj0A,Matias Marolla
|
UC0hHW5Y08ggq-9kbrGgWj0A,http://www.youtube.com/channel/UC0hHW5Y08ggq-9kbrGgWj0A,Matias Marolla
|
||||||
UC0vBXGSyV14uvJ4hECDOl0Q,http://www.youtube.com/channel/UC0vBXGSyV14uvJ4hECDOl0Q,Techquickie
|
UC0vBXGSyV14uvJ4hECDOl0Q,http://www.youtube.com/channel/UC0vBXGSyV14uvJ4hECDOl0Q,Techquickie
|
||||||
UC1sELGmy5jp5fQUugmuYlXQ,http://www.youtube.com/channel/UC1sELGmy5jp5fQUugmuYlXQ,Minecraft
|
UC1sELGmy5jp5fQUugmuYlXQ,http://www.youtube.com/channel/UC1sELGmy5jp5fQUugmuYlXQ,Minecraft
|
||||||
UC9kFnwdCRrX7oTjqKd6-tiQ,http://www.youtube.com/channel/UC9kFnwdCRrX7oTjqKd6-tiQ,LUMOX - Topic
|
UC9kFnwdCRrX7oTjqKd6-tiQ,http://www.youtube.com/channel/UC9kFnwdCRrX7oTjqKd6-tiQ,LUMOX - Topic
|
||||||
UCBa659QWEk1AI4Tg--mrJ2A,http://www.youtube.com/channel/UCBa659QWEk1AI4Tg--mrJ2A,Tom Scott
|
UCBa659QWEk1AI4Tg--mrJ2A,http://www.youtube.com/channel/UCBa659QWEk1AI4Tg--mrJ2A,Tom Scott
|
||||||
UCGu6_XQ64rXPR6nuitMQE_A,http://www.youtube.com/channel/UCGu6_XQ64rXPR6nuitMQE_A,Callcenter Fun
|
UCGu6_XQ64rXPR6nuitMQE_A,http://www.youtube.com/channel/UCGu6_XQ64rXPR6nuitMQE_A,Callcenter Fun
|
||||||
UCGwu0nbY2wSkW8N-cghnLpA,http://www.youtube.com/channel/UCGwu0nbY2wSkW8N-cghnLpA,Jaiden Animations
|
UCGwu0nbY2wSkW8N-cghnLpA,http://www.youtube.com/channel/UCGwu0nbY2wSkW8N-cghnLpA,Jaiden Animations
|
||||||
UCQ0OvZ54pCFZwsKxbltg_tg,http://www.youtube.com/channel/UCQ0OvZ54pCFZwsKxbltg_tg,Methos
|
UCQ0OvZ54pCFZwsKxbltg_tg,http://www.youtube.com/channel/UCQ0OvZ54pCFZwsKxbltg_tg,Methos
|
||||||
UCRE6itj4Jte4manQEu3Y7OA,http://www.youtube.com/channel/UCRE6itj4Jte4manQEu3Y7OA,Chipflake
|
UCRE6itj4Jte4manQEu3Y7OA,http://www.youtube.com/channel/UCRE6itj4Jte4manQEu3Y7OA,Chipflake
|
||||||
UCRLc6zsv_d0OEBO8OOkz-DA,http://www.youtube.com/channel/UCRLc6zsv_d0OEBO8OOkz-DA,Kegy
|
UCRLc6zsv_d0OEBO8OOkz-DA,http://www.youtube.com/channel/UCRLc6zsv_d0OEBO8OOkz-DA,Kegy
|
||||||
UCSl5Uxu2LyaoAoMMGp6oTJA,http://www.youtube.com/channel/UCSl5Uxu2LyaoAoMMGp6oTJA,Atomic Shrimp
|
UCSl5Uxu2LyaoAoMMGp6oTJA,http://www.youtube.com/channel/UCSl5Uxu2LyaoAoMMGp6oTJA,Atomic Shrimp
|
||||||
UCXuqSBlHAE6Xw-yeJA0Tunw,http://www.youtube.com/channel/UCXuqSBlHAE6Xw-yeJA0Tunw,Linus Tech Tips
|
UCXuqSBlHAE6Xw-yeJA0Tunw,http://www.youtube.com/channel/UCXuqSBlHAE6Xw-yeJA0Tunw,Linus Tech Tips
|
||||||
UCZ5XnGb-3t7jCkXdawN2tkA,http://www.youtube.com/channel/UCZ5XnGb-3t7jCkXdawN2tkA,Discord
|
UCZ5XnGb-3t7jCkXdawN2tkA,http://www.youtube.com/channel/UCZ5XnGb-3t7jCkXdawN2tkA,Discord
|
||||||
CSV
|
CSV
|
||||||
end
|
end
|
||||||
|
|
||||||
Spectator.describe Invidious::User::Import do
|
Spectator.describe Invidious::User::Import do
|
||||||
|
|||||||
@ -123,7 +123,7 @@ Kemal.config.extra_options do |parser|
|
|||||||
parser.on("-c THREADS", "--channel-threads=THREADS", "Number of threads for refreshing channels (default: #{CONFIG.channel_threads})") do |number|
|
parser.on("-c THREADS", "--channel-threads=THREADS", "Number of threads for refreshing channels (default: #{CONFIG.channel_threads})") do |number|
|
||||||
begin
|
begin
|
||||||
CONFIG.channel_threads = number.to_i
|
CONFIG.channel_threads = number.to_i
|
||||||
rescue ex
|
rescue
|
||||||
puts "THREADS must be integer"
|
puts "THREADS must be integer"
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
@ -131,7 +131,7 @@ Kemal.config.extra_options do |parser|
|
|||||||
parser.on("-f THREADS", "--feed-threads=THREADS", "Number of threads for refreshing feeds (default: #{CONFIG.feed_threads})") do |number|
|
parser.on("-f THREADS", "--feed-threads=THREADS", "Number of threads for refreshing feeds (default: #{CONFIG.feed_threads})") do |number|
|
||||||
begin
|
begin
|
||||||
CONFIG.feed_threads = number.to_i
|
CONFIG.feed_threads = number.to_i
|
||||||
rescue ex
|
rescue
|
||||||
puts "THREADS must be integer"
|
puts "THREADS must be integer"
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
|
|||||||
@ -93,7 +93,7 @@ struct ChannelVideo
|
|||||||
def to_tuple
|
def to_tuple
|
||||||
{% begin %}
|
{% begin %}
|
||||||
{
|
{
|
||||||
{{@type.instance_vars.map(&.name).splat}}
|
{{ @type.instance_vars.map(&.name).splat }}
|
||||||
}
|
}
|
||||||
{% end %}
|
{% end %}
|
||||||
end
|
end
|
||||||
@ -107,7 +107,7 @@ class ChannelRedirect < Exception
|
|||||||
end
|
end
|
||||||
|
|
||||||
def get_batch_channels(channels)
|
def get_batch_channels(channels)
|
||||||
finished_channel = Channel(String | Nil).new
|
finished_channel = Channel(String?).new
|
||||||
max_threads = 10
|
max_threads = 10
|
||||||
|
|
||||||
spawn do
|
spawn do
|
||||||
@ -125,7 +125,7 @@ def get_batch_channels(channels)
|
|||||||
begin
|
begin
|
||||||
get_channel(ucid)
|
get_channel(ucid)
|
||||||
finished_channel.send(ucid)
|
finished_channel.send(ucid)
|
||||||
rescue ex
|
rescue
|
||||||
finished_channel.send(nil)
|
finished_channel.send(nil)
|
||||||
ensure
|
ensure
|
||||||
active_channel.send(nil)
|
active_channel.send(nil)
|
||||||
|
|||||||
@ -15,7 +15,7 @@ module Invidious::Comments
|
|||||||
|
|
||||||
if url.host.nil? || url.host.not_nil!.ends_with?("youtube.com") || url.host.not_nil!.ends_with?("youtu.be")
|
if url.host.nil? || url.host.not_nil!.ends_with?("youtube.com") || url.host.not_nil!.ends_with?("youtu.be")
|
||||||
if url.host.try &.ends_with? "youtu.be"
|
if url.host.try &.ends_with? "youtu.be"
|
||||||
url = "/watch?v=#{url.path.lstrip('/')}#{url.query_params}"
|
anchor["href"] = "/watch?v=#{url.path.lstrip('/')}#{url.query_params}"
|
||||||
else
|
else
|
||||||
if url.path == "/redirect"
|
if url.path == "/redirect"
|
||||||
params = HTTP::Params.parse(url.query.not_nil!)
|
params = HTTP::Params.parse(url.query.not_nil!)
|
||||||
@ -27,7 +27,7 @@ module Invidious::Comments
|
|||||||
elsif url.to_s == "#"
|
elsif url.to_s == "#"
|
||||||
begin
|
begin
|
||||||
length_seconds = decode_length_seconds(anchor.content)
|
length_seconds = decode_length_seconds(anchor.content)
|
||||||
rescue ex
|
rescue
|
||||||
length_seconds = decode_time(anchor.content)
|
length_seconds = decode_time(anchor.content)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -59,7 +59,7 @@ struct ConfigPreferences
|
|||||||
def to_tuple
|
def to_tuple
|
||||||
{% begin %}
|
{% begin %}
|
||||||
{
|
{
|
||||||
{{(@type.instance_vars.map { |var| "#{var.name}: #{var.name}".id }).splat}}
|
{{ (@type.instance_vars.map { |var| "#{var.name}: #{var.name}".id }).splat }}
|
||||||
}
|
}
|
||||||
{% end %}
|
{% end %}
|
||||||
end
|
end
|
||||||
@ -237,14 +237,14 @@ class Config
|
|||||||
{% for ivar in Config.instance_vars %}
|
{% for ivar in Config.instance_vars %}
|
||||||
{% env_id = "INVIDIOUS_#{ivar.id.upcase}" %}
|
{% env_id = "INVIDIOUS_#{ivar.id.upcase}" %}
|
||||||
|
|
||||||
if ENV.has_key?({{env_id}})
|
if ENV.has_key?({{ env_id }})
|
||||||
env_value = ENV.fetch({{env_id}})
|
env_value = ENV.fetch({{ env_id }})
|
||||||
success = false
|
success = false
|
||||||
|
|
||||||
# Use YAML converter if specified
|
# Use YAML converter if specified
|
||||||
{% ann = ivar.annotation(::YAML::Field) %}
|
{% ann = ivar.annotation(::YAML::Field) %}
|
||||||
{% if ann && ann[:converter] %}
|
{% if ann && ann[:converter] %}
|
||||||
config.{{ivar.id}} = {{ann[:converter]}}.from_yaml(YAML::ParseContext.new, YAML::Nodes.parse(ENV.fetch({{env_id}})).nodes[0])
|
config.{{ ivar.id }} = {{ ann[:converter] }}.from_yaml(YAML::ParseContext.new, YAML::Nodes.parse(ENV.fetch({{ env_id }})).nodes[0])
|
||||||
success = true
|
success = true
|
||||||
|
|
||||||
# Use regular YAML parser otherwise
|
# Use regular YAML parser otherwise
|
||||||
@ -252,10 +252,10 @@ class Config
|
|||||||
{% ivar_types = ivar.type.union? ? ivar.type.union_types : [ivar.type] %}
|
{% ivar_types = ivar.type.union? ? ivar.type.union_types : [ivar.type] %}
|
||||||
# Sort types to avoid parsing nulls and numbers as strings
|
# 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 = ivar_types.sort_by { |ivar_type| ivar_type == Nil ? 0 : ivar_type == Int32 ? 1 : 2 } %}
|
||||||
{{ivar_types}}.each do |ivar_type|
|
{{ ivar_types }}.each do |ivar_type|
|
||||||
if !success
|
if !success
|
||||||
begin
|
begin
|
||||||
config.{{ivar.id}} = ivar_type.from_yaml(env_value)
|
config.{{ ivar.id }} = ivar_type.from_yaml(env_value)
|
||||||
success = true
|
success = true
|
||||||
rescue
|
rescue
|
||||||
# nop
|
# nop
|
||||||
@ -266,14 +266,14 @@ class Config
|
|||||||
|
|
||||||
# Exit on fail
|
# Exit on fail
|
||||||
if !success
|
if !success
|
||||||
puts %(Config.{{ivar.id}} failed to parse #{env_value} as {{ivar.type}})
|
puts %(Config.{{ ivar.id }} failed to parse #{env_value} as {{ ivar.type }})
|
||||||
exit(1)
|
exit(1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Warn when any config attribute is set to "CHANGE_ME!!"
|
# Warn when any config attribute is set to "CHANGE_ME!!"
|
||||||
if config.{{ivar.id}} == "CHANGE_ME!!"
|
if config.{{ ivar.id }} == "CHANGE_ME!!"
|
||||||
puts "Config: The value of '#{ {{ivar.stringify}} }' needs to be changed!!"
|
puts "Config: The value of '#{ {{ ivar.stringify }} }' needs to be changed!!"
|
||||||
exit(1)
|
exit(1)
|
||||||
end
|
end
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ module Invidious::Database::Annotations
|
|||||||
INSERT INTO annotations
|
INSERT INTO annotations
|
||||||
VALUES ($1, $2)
|
VALUES ($1, $2)
|
||||||
ON CONFLICT DO NOTHING
|
ON CONFLICT DO NOTHING
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, id, annotations)
|
PG_DB.exec(request, id, annotations)
|
||||||
end
|
end
|
||||||
@ -17,7 +17,7 @@ module Invidious::Database::Annotations
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT * FROM annotations
|
SELECT * FROM annotations
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_one?(request, id, as: Annotation)
|
return PG_DB.query_one?(request, id, as: Annotation)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -45,7 +45,7 @@ module Invidious::Database
|
|||||||
# Create table if it doesn't exist
|
# Create table if it doesn't exist
|
||||||
begin
|
begin
|
||||||
PG_DB.exec("SELECT * FROM #{table_name} LIMIT 0")
|
PG_DB.exec("SELECT * FROM #{table_name} LIMIT 0")
|
||||||
rescue ex
|
rescue
|
||||||
LOGGER.info("check_table: check_table: CREATE TABLE #{table_name}")
|
LOGGER.info("check_table: check_table: CREATE TABLE #{table_name}")
|
||||||
|
|
||||||
PG_DB.using_connection do |conn|
|
PG_DB.using_connection do |conn|
|
||||||
|
|||||||
@ -16,13 +16,13 @@ module Invidious::Database::Channels
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
INSERT INTO channels
|
INSERT INTO channels
|
||||||
VALUES (#{arg_array(channel_array)})
|
VALUES (#{arg_array(channel_array)})
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
if update_on_conflict
|
if update_on_conflict
|
||||||
request += <<-SQL
|
request += <<-SQL
|
||||||
ON CONFLICT (id) DO UPDATE
|
ON CONFLICT (id) DO UPDATE
|
||||||
SET author = $2, updated = $3
|
SET author = $2, updated = $3
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
|
|
||||||
PG_DB.exec(request, args: channel_array)
|
PG_DB.exec(request, args: channel_array)
|
||||||
@ -37,7 +37,7 @@ module Invidious::Database::Channels
|
|||||||
UPDATE channels
|
UPDATE channels
|
||||||
SET updated = now(), author = $1, deleted = false
|
SET updated = now(), author = $1, deleted = false
|
||||||
WHERE id = $2
|
WHERE id = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, author, id)
|
PG_DB.exec(request, author, id)
|
||||||
end
|
end
|
||||||
@ -47,7 +47,7 @@ module Invidious::Database::Channels
|
|||||||
UPDATE channels
|
UPDATE channels
|
||||||
SET subscribed = now()
|
SET subscribed = now()
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, id)
|
PG_DB.exec(request, id)
|
||||||
end
|
end
|
||||||
@ -57,7 +57,7 @@ module Invidious::Database::Channels
|
|||||||
UPDATE channels
|
UPDATE channels
|
||||||
SET updated = now(), deleted = true
|
SET updated = now(), deleted = true
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, id)
|
PG_DB.exec(request, id)
|
||||||
end
|
end
|
||||||
@ -70,7 +70,7 @@ module Invidious::Database::Channels
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT * FROM channels
|
SELECT * FROM channels
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_one?(request, id, as: InvidiousChannel)
|
return PG_DB.query_one?(request, id, as: InvidiousChannel)
|
||||||
end
|
end
|
||||||
@ -81,7 +81,7 @@ module Invidious::Database::Channels
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT * FROM channels
|
SELECT * FROM channels
|
||||||
WHERE id = ANY($1)
|
WHERE id = ANY($1)
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_all(request, ids, as: InvidiousChannel)
|
return PG_DB.query_all(request, ids, as: InvidiousChannel)
|
||||||
end
|
end
|
||||||
@ -112,7 +112,7 @@ module Invidious::Database::ChannelVideos
|
|||||||
SET title = $2, published = $3, updated = $4, ucid = $5,
|
SET title = $2, published = $3, updated = $4, ucid = $5,
|
||||||
author = $6, length_seconds = $7, live_now = $8, #{last_items}
|
author = $6, length_seconds = $7, live_now = $8, #{last_items}
|
||||||
RETURNING (xmax=0) AS was_insert
|
RETURNING (xmax=0) AS was_insert
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_one(request, *video.to_tuple, as: Bool)
|
return PG_DB.query_one(request, *video.to_tuple, as: Bool)
|
||||||
end
|
end
|
||||||
@ -128,7 +128,7 @@ module Invidious::Database::ChannelVideos
|
|||||||
SELECT * FROM channel_videos
|
SELECT * FROM channel_videos
|
||||||
WHERE id = ANY($1)
|
WHERE id = ANY($1)
|
||||||
ORDER BY published DESC
|
ORDER BY published DESC
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_all(request, ids, as: ChannelVideo)
|
return PG_DB.query_all(request, ids, as: ChannelVideo)
|
||||||
end
|
end
|
||||||
@ -139,7 +139,7 @@ module Invidious::Database::ChannelVideos
|
|||||||
WHERE ucid = $1 AND published > $2
|
WHERE ucid = $1 AND published > $2
|
||||||
ORDER BY published DESC
|
ORDER BY published DESC
|
||||||
LIMIT 15
|
LIMIT 15
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_all(request, ucid, since, as: ChannelVideo)
|
return PG_DB.query_all(request, ucid, since, as: ChannelVideo)
|
||||||
end
|
end
|
||||||
@ -151,7 +151,7 @@ module Invidious::Database::ChannelVideos
|
|||||||
WHERE ucid IN (SELECT channel FROM (SELECT UNNEST(subscriptions) AS channel FROM users) AS d
|
WHERE ucid IN (SELECT channel FROM (SELECT UNNEST(subscriptions) AS channel FROM users) AS d
|
||||||
GROUP BY channel ORDER BY COUNT(channel) DESC LIMIT 40)
|
GROUP BY channel ORDER BY COUNT(channel) DESC LIMIT 40)
|
||||||
ORDER BY ucid, published DESC
|
ORDER BY ucid, published DESC
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.query_all(request, as: ChannelVideo)
|
PG_DB.query_all(request, as: ChannelVideo)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -4,27 +4,27 @@ module Invidious::Database::Migrations
|
|||||||
|
|
||||||
def up(conn : DB::Connection)
|
def up(conn : DB::Connection)
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE TABLE IF NOT EXISTS public.channels
|
CREATE TABLE IF NOT EXISTS public.channels
|
||||||
(
|
(
|
||||||
id text NOT NULL,
|
id text NOT NULL,
|
||||||
author text,
|
author text,
|
||||||
updated timestamp with time zone,
|
updated timestamp with time zone,
|
||||||
deleted boolean,
|
deleted boolean,
|
||||||
subscribed timestamp with time zone,
|
subscribed timestamp with time zone,
|
||||||
CONSTRAINT channels_id_key UNIQUE (id)
|
CONSTRAINT channels_id_key UNIQUE (id)
|
||||||
);
|
);
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
GRANT ALL ON TABLE public.channels TO current_user;
|
GRANT ALL ON TABLE public.channels TO current_user;
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE INDEX IF NOT EXISTS channels_id_idx
|
CREATE INDEX IF NOT EXISTS channels_id_idx
|
||||||
ON public.channels
|
ON public.channels
|
||||||
USING btree
|
USING btree
|
||||||
(id COLLATE pg_catalog."default");
|
(id COLLATE pg_catalog."default");
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -4,25 +4,25 @@ module Invidious::Database::Migrations
|
|||||||
|
|
||||||
def up(conn : DB::Connection)
|
def up(conn : DB::Connection)
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE UNLOGGED TABLE IF NOT EXISTS public.videos
|
CREATE UNLOGGED TABLE IF NOT EXISTS public.videos
|
||||||
(
|
(
|
||||||
id text NOT NULL,
|
id text NOT NULL,
|
||||||
info text,
|
info text,
|
||||||
updated timestamp with time zone,
|
updated timestamp with time zone,
|
||||||
CONSTRAINT videos_pkey PRIMARY KEY (id)
|
CONSTRAINT videos_pkey PRIMARY KEY (id)
|
||||||
);
|
);
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
GRANT ALL ON TABLE public.videos TO current_user;
|
GRANT ALL ON TABLE public.videos TO current_user;
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS id_idx
|
CREATE UNIQUE INDEX IF NOT EXISTS id_idx
|
||||||
ON public.videos
|
ON public.videos
|
||||||
USING btree
|
USING btree
|
||||||
(id COLLATE pg_catalog."default");
|
(id COLLATE pg_catalog."default");
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -4,32 +4,32 @@ module Invidious::Database::Migrations
|
|||||||
|
|
||||||
def up(conn : DB::Connection)
|
def up(conn : DB::Connection)
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE TABLE IF NOT EXISTS public.channel_videos
|
CREATE TABLE IF NOT EXISTS public.channel_videos
|
||||||
(
|
(
|
||||||
id text NOT NULL,
|
id text NOT NULL,
|
||||||
title text,
|
title text,
|
||||||
published timestamp with time zone,
|
published timestamp with time zone,
|
||||||
updated timestamp with time zone,
|
updated timestamp with time zone,
|
||||||
ucid text,
|
ucid text,
|
||||||
author text,
|
author text,
|
||||||
length_seconds integer,
|
length_seconds integer,
|
||||||
live_now boolean,
|
live_now boolean,
|
||||||
premiere_timestamp timestamp with time zone,
|
premiere_timestamp timestamp with time zone,
|
||||||
views bigint,
|
views bigint,
|
||||||
CONSTRAINT channel_videos_id_key UNIQUE (id)
|
CONSTRAINT channel_videos_id_key UNIQUE (id)
|
||||||
);
|
);
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
GRANT ALL ON TABLE public.channel_videos TO current_user;
|
GRANT ALL ON TABLE public.channel_videos TO current_user;
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE INDEX IF NOT EXISTS channel_videos_ucid_idx
|
CREATE INDEX IF NOT EXISTS channel_videos_ucid_idx
|
||||||
ON public.channel_videos
|
ON public.channel_videos
|
||||||
USING btree
|
USING btree
|
||||||
(ucid COLLATE pg_catalog."default");
|
(ucid COLLATE pg_catalog."default");
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -4,31 +4,31 @@ module Invidious::Database::Migrations
|
|||||||
|
|
||||||
def up(conn : DB::Connection)
|
def up(conn : DB::Connection)
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE TABLE IF NOT EXISTS public.users
|
CREATE TABLE IF NOT EXISTS public.users
|
||||||
(
|
(
|
||||||
updated timestamp with time zone,
|
updated timestamp with time zone,
|
||||||
notifications text[],
|
notifications text[],
|
||||||
subscriptions text[],
|
subscriptions text[],
|
||||||
email text NOT NULL,
|
email text NOT NULL,
|
||||||
preferences text,
|
preferences text,
|
||||||
password text,
|
password text,
|
||||||
token text,
|
token text,
|
||||||
watched text[],
|
watched text[],
|
||||||
feed_needs_update boolean,
|
feed_needs_update boolean,
|
||||||
CONSTRAINT users_email_key UNIQUE (email)
|
CONSTRAINT users_email_key UNIQUE (email)
|
||||||
);
|
);
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
GRANT ALL ON TABLE public.users TO current_user;
|
GRANT ALL ON TABLE public.users TO current_user;
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS email_unique_idx
|
CREATE UNIQUE INDEX IF NOT EXISTS email_unique_idx
|
||||||
ON public.users
|
ON public.users
|
||||||
USING btree
|
USING btree
|
||||||
(lower(email) COLLATE pg_catalog."default");
|
(lower(email) COLLATE pg_catalog."default");
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -4,25 +4,25 @@ module Invidious::Database::Migrations
|
|||||||
|
|
||||||
def up(conn : DB::Connection)
|
def up(conn : DB::Connection)
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE TABLE IF NOT EXISTS public.session_ids
|
CREATE TABLE IF NOT EXISTS public.session_ids
|
||||||
(
|
(
|
||||||
id text NOT NULL,
|
id text NOT NULL,
|
||||||
email text,
|
email text,
|
||||||
issued timestamp with time zone,
|
issued timestamp with time zone,
|
||||||
CONSTRAINT session_ids_pkey PRIMARY KEY (id)
|
CONSTRAINT session_ids_pkey PRIMARY KEY (id)
|
||||||
);
|
);
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
GRANT ALL ON TABLE public.session_ids TO current_user;
|
GRANT ALL ON TABLE public.session_ids TO current_user;
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE INDEX IF NOT EXISTS session_ids_id_idx
|
CREATE INDEX IF NOT EXISTS session_ids_id_idx
|
||||||
ON public.session_ids
|
ON public.session_ids
|
||||||
USING btree
|
USING btree
|
||||||
(id COLLATE pg_catalog."default");
|
(id COLLATE pg_catalog."default");
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -4,24 +4,24 @@ module Invidious::Database::Migrations
|
|||||||
|
|
||||||
def up(conn : DB::Connection)
|
def up(conn : DB::Connection)
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE TABLE IF NOT EXISTS public.nonces
|
CREATE TABLE IF NOT EXISTS public.nonces
|
||||||
(
|
(
|
||||||
nonce text,
|
nonce text,
|
||||||
expire timestamp with time zone,
|
expire timestamp with time zone,
|
||||||
CONSTRAINT nonces_id_key UNIQUE (nonce)
|
CONSTRAINT nonces_id_key UNIQUE (nonce)
|
||||||
);
|
);
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
GRANT ALL ON TABLE public.nonces TO current_user;
|
GRANT ALL ON TABLE public.nonces TO current_user;
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE INDEX IF NOT EXISTS nonces_nonce_idx
|
CREATE INDEX IF NOT EXISTS nonces_nonce_idx
|
||||||
ON public.nonces
|
ON public.nonces
|
||||||
USING btree
|
USING btree
|
||||||
(nonce COLLATE pg_catalog."default");
|
(nonce COLLATE pg_catalog."default");
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -4,17 +4,17 @@ module Invidious::Database::Migrations
|
|||||||
|
|
||||||
def up(conn : DB::Connection)
|
def up(conn : DB::Connection)
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE TABLE IF NOT EXISTS public.annotations
|
CREATE TABLE IF NOT EXISTS public.annotations
|
||||||
(
|
(
|
||||||
id text NOT NULL,
|
id text NOT NULL,
|
||||||
annotations xml,
|
annotations xml,
|
||||||
CONSTRAINT annotations_id_key UNIQUE (id)
|
CONSTRAINT annotations_id_key UNIQUE (id)
|
||||||
);
|
);
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
GRANT ALL ON TABLE public.annotations TO current_user;
|
GRANT ALL ON TABLE public.annotations TO current_user;
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -5,33 +5,33 @@ module Invidious::Database::Migrations
|
|||||||
def up(conn : DB::Connection)
|
def up(conn : DB::Connection)
|
||||||
if !privacy_type_exists?(conn)
|
if !privacy_type_exists?(conn)
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE TYPE public.privacy AS ENUM
|
CREATE TYPE public.privacy AS ENUM
|
||||||
(
|
(
|
||||||
'Public',
|
'Public',
|
||||||
'Unlisted',
|
'Unlisted',
|
||||||
'Private'
|
'Private'
|
||||||
);
|
);
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE TABLE IF NOT EXISTS public.playlists
|
CREATE TABLE IF NOT EXISTS public.playlists
|
||||||
(
|
(
|
||||||
title text,
|
title text,
|
||||||
id text primary key,
|
id text primary key,
|
||||||
author text,
|
author text,
|
||||||
description text,
|
description text,
|
||||||
video_count integer,
|
video_count integer,
|
||||||
created timestamptz,
|
created timestamptz,
|
||||||
updated timestamptz,
|
updated timestamptz,
|
||||||
privacy privacy,
|
privacy privacy,
|
||||||
index int8[]
|
index int8[]
|
||||||
);
|
);
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
GRANT ALL ON public.playlists TO current_user;
|
GRANT ALL ON public.playlists TO current_user;
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
|
|
||||||
private def privacy_type_exists?(conn : DB::Connection) : Bool
|
private def privacy_type_exists?(conn : DB::Connection) : Bool
|
||||||
@ -42,7 +42,7 @@ module Invidious::Database::Migrations
|
|||||||
WHERE pg_namespace.nspname = 'public'
|
WHERE pg_namespace.nspname = 'public'
|
||||||
AND pg_type.typname = 'privacy'
|
AND pg_type.typname = 'privacy'
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
!conn.query_one?(request, as: Int32).nil?
|
!conn.query_one?(request, as: Int32).nil?
|
||||||
end
|
end
|
||||||
|
|||||||
@ -4,24 +4,24 @@ module Invidious::Database::Migrations
|
|||||||
|
|
||||||
def up(conn : DB::Connection)
|
def up(conn : DB::Connection)
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
CREATE TABLE IF NOT EXISTS public.playlist_videos
|
CREATE TABLE IF NOT EXISTS public.playlist_videos
|
||||||
(
|
(
|
||||||
title text,
|
title text,
|
||||||
id text,
|
id text,
|
||||||
author text,
|
author text,
|
||||||
ucid text,
|
ucid text,
|
||||||
length_seconds integer,
|
length_seconds integer,
|
||||||
published timestamptz,
|
published timestamptz,
|
||||||
plid text references playlists(id),
|
plid text references playlists(id),
|
||||||
index int8,
|
index int8,
|
||||||
live_now boolean,
|
live_now boolean,
|
||||||
PRIMARY KEY (index,plid)
|
PRIMARY KEY (index,plid)
|
||||||
);
|
);
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
GRANT ALL ON TABLE public.playlist_videos TO current_user;
|
GRANT ALL ON TABLE public.playlist_videos TO current_user;
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -4,8 +4,8 @@ module Invidious::Database::Migrations
|
|||||||
|
|
||||||
def up(conn : DB::Connection)
|
def up(conn : DB::Connection)
|
||||||
conn.exec <<-SQL
|
conn.exec <<-SQL
|
||||||
ALTER TABLE public.videos SET UNLOGGED;
|
ALTER TABLE public.videos SET UNLOGGED;
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -44,6 +44,6 @@ class Invidious::Database::Migrator
|
|||||||
id bigserial PRIMARY KEY,
|
id bigserial PRIMARY KEY,
|
||||||
version bigint NOT NULL
|
version bigint NOT NULL
|
||||||
)
|
)
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -12,7 +12,7 @@ module Invidious::Database::Nonces
|
|||||||
INSERT INTO nonces
|
INSERT INTO nonces
|
||||||
VALUES ($1, $2)
|
VALUES ($1, $2)
|
||||||
ON CONFLICT DO NOTHING
|
ON CONFLICT DO NOTHING
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, nonce, expire)
|
PG_DB.exec(request, nonce, expire)
|
||||||
end
|
end
|
||||||
@ -21,7 +21,7 @@ module Invidious::Database::Nonces
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
DELETE FROM nonces *
|
DELETE FROM nonces *
|
||||||
WHERE expire < now()
|
WHERE expire < now()
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request)
|
PG_DB.exec(request)
|
||||||
end
|
end
|
||||||
@ -35,7 +35,7 @@ module Invidious::Database::Nonces
|
|||||||
UPDATE nonces
|
UPDATE nonces
|
||||||
SET expire = $1
|
SET expire = $1
|
||||||
WHERE nonce = $2
|
WHERE nonce = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, Time.utc(1990, 1, 1), nonce)
|
PG_DB.exec(request, Time.utc(1990, 1, 1), nonce)
|
||||||
end
|
end
|
||||||
@ -48,7 +48,7 @@ module Invidious::Database::Nonces
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT * FROM nonces
|
SELECT * FROM nonces
|
||||||
WHERE nonce = $1
|
WHERE nonce = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_one?(request, nonce, as: {String, Time})
|
return PG_DB.query_one?(request, nonce, as: {String, Time})
|
||||||
end
|
end
|
||||||
|
|||||||
@ -16,7 +16,7 @@ module Invidious::Database::Playlists
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
INSERT INTO playlists
|
INSERT INTO playlists
|
||||||
VALUES (#{arg_array(playlist_array)})
|
VALUES (#{arg_array(playlist_array)})
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, args: playlist_array)
|
PG_DB.exec(request, args: playlist_array)
|
||||||
end
|
end
|
||||||
@ -27,7 +27,7 @@ module Invidious::Database::Playlists
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
DELETE FROM playlists *
|
DELETE FROM playlists *
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, id)
|
PG_DB.exec(request, id)
|
||||||
end
|
end
|
||||||
@ -41,7 +41,7 @@ module Invidious::Database::Playlists
|
|||||||
UPDATE playlists
|
UPDATE playlists
|
||||||
SET title = $1, privacy = $2, description = $3, updated = $4
|
SET title = $1, privacy = $2, description = $3, updated = $4
|
||||||
WHERE id = $5
|
WHERE id = $5
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, title, privacy, description, updated, id)
|
PG_DB.exec(request, title, privacy, description, updated, id)
|
||||||
end
|
end
|
||||||
@ -51,7 +51,7 @@ module Invidious::Database::Playlists
|
|||||||
UPDATE playlists
|
UPDATE playlists
|
||||||
SET description = $1
|
SET description = $1
|
||||||
WHERE id = $2
|
WHERE id = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, description, id)
|
PG_DB.exec(request, description, id)
|
||||||
end
|
end
|
||||||
@ -61,7 +61,7 @@ module Invidious::Database::Playlists
|
|||||||
UPDATE playlists
|
UPDATE playlists
|
||||||
SET subscribed = now()
|
SET subscribed = now()
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, id)
|
PG_DB.exec(request, id)
|
||||||
end
|
end
|
||||||
@ -73,7 +73,7 @@ module Invidious::Database::Playlists
|
|||||||
video_count = cardinality(index) + 1,
|
video_count = cardinality(index) + 1,
|
||||||
updated = now()
|
updated = now()
|
||||||
WHERE id = $2
|
WHERE id = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, index, id)
|
PG_DB.exec(request, index, id)
|
||||||
end
|
end
|
||||||
@ -85,7 +85,7 @@ module Invidious::Database::Playlists
|
|||||||
video_count = cardinality(index) - 1,
|
video_count = cardinality(index) - 1,
|
||||||
updated = now()
|
updated = now()
|
||||||
WHERE id = $2
|
WHERE id = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, index, id)
|
PG_DB.exec(request, index, id)
|
||||||
end
|
end
|
||||||
@ -98,7 +98,7 @@ module Invidious::Database::Playlists
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT * FROM playlists
|
SELECT * FROM playlists
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_one?(request, id, as: InvidiousPlaylist)
|
return PG_DB.query_one?(request, id, as: InvidiousPlaylist)
|
||||||
end
|
end
|
||||||
@ -107,7 +107,7 @@ module Invidious::Database::Playlists
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT * FROM playlists
|
SELECT * FROM playlists
|
||||||
WHERE author = $1
|
WHERE author = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_all(request, author, as: InvidiousPlaylist)
|
return PG_DB.query_all(request, author, as: InvidiousPlaylist)
|
||||||
end
|
end
|
||||||
@ -121,7 +121,7 @@ module Invidious::Database::Playlists
|
|||||||
SELECT * FROM playlists
|
SELECT * FROM playlists
|
||||||
WHERE author = $1 AND id LIKE 'IV%'
|
WHERE author = $1 AND id LIKE 'IV%'
|
||||||
ORDER BY created
|
ORDER BY created
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.query_all(request, email, as: InvidiousPlaylist)
|
PG_DB.query_all(request, email, as: InvidiousPlaylist)
|
||||||
end
|
end
|
||||||
@ -131,7 +131,7 @@ module Invidious::Database::Playlists
|
|||||||
SELECT * FROM playlists
|
SELECT * FROM playlists
|
||||||
WHERE author = $1 AND id NOT LIKE 'IV%'
|
WHERE author = $1 AND id NOT LIKE 'IV%'
|
||||||
ORDER BY created
|
ORDER BY created
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.query_all(request, email, as: InvidiousPlaylist)
|
PG_DB.query_all(request, email, as: InvidiousPlaylist)
|
||||||
end
|
end
|
||||||
@ -141,7 +141,7 @@ module Invidious::Database::Playlists
|
|||||||
SELECT id,title FROM playlists
|
SELECT id,title FROM playlists
|
||||||
WHERE author = $1 AND id LIKE 'IV%'
|
WHERE author = $1 AND id LIKE 'IV%'
|
||||||
ORDER BY title
|
ORDER BY title
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.query_all(request, email, as: {String, String})
|
PG_DB.query_all(request, email, as: {String, String})
|
||||||
end
|
end
|
||||||
@ -155,7 +155,7 @@ module Invidious::Database::Playlists
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT id FROM playlists
|
SELECT id FROM playlists
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_one?(request, id, as: String).nil?
|
return PG_DB.query_one?(request, id, as: String).nil?
|
||||||
end
|
end
|
||||||
@ -165,7 +165,7 @@ module Invidious::Database::Playlists
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT count(*) FROM playlists
|
SELECT count(*) FROM playlists
|
||||||
WHERE author = $1
|
WHERE author = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_one?(request, author, as: Int64) || 0_i64
|
return PG_DB.query_one?(request, author, as: Int64) || 0_i64
|
||||||
end
|
end
|
||||||
@ -189,7 +189,7 @@ module Invidious::Database::PlaylistVideos
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
INSERT INTO playlist_videos
|
INSERT INTO playlist_videos
|
||||||
VALUES (#{arg_array(video_array)})
|
VALUES (#{arg_array(video_array)})
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, args: video_array)
|
PG_DB.exec(request, args: video_array)
|
||||||
end
|
end
|
||||||
@ -198,7 +198,7 @@ module Invidious::Database::PlaylistVideos
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
DELETE FROM playlist_videos *
|
DELETE FROM playlist_videos *
|
||||||
WHERE index = $1 AND plid = $2
|
WHERE index = $1 AND plid = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, index, plid)
|
PG_DB.exec(request, index, plid)
|
||||||
end
|
end
|
||||||
@ -207,7 +207,7 @@ module Invidious::Database::PlaylistVideos
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
DELETE FROM playlist_videos *
|
DELETE FROM playlist_videos *
|
||||||
WHERE plid = $1
|
WHERE plid = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, plid)
|
PG_DB.exec(request, plid)
|
||||||
end
|
end
|
||||||
@ -223,7 +223,7 @@ module Invidious::Database::PlaylistVideos
|
|||||||
ORDER BY array_position($2, index)
|
ORDER BY array_position($2, index)
|
||||||
LIMIT $3
|
LIMIT $3
|
||||||
OFFSET $4
|
OFFSET $4
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_all(request, plid, index, limit, offset, as: PlaylistVideo)
|
return PG_DB.query_all(request, plid, index, limit, offset, as: PlaylistVideo)
|
||||||
end
|
end
|
||||||
@ -233,7 +233,7 @@ module Invidious::Database::PlaylistVideos
|
|||||||
SELECT index FROM playlist_videos
|
SELECT index FROM playlist_videos
|
||||||
WHERE plid = $1 AND id = $2
|
WHERE plid = $1 AND id = $2
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_one?(request, plid, vid, as: Int64)
|
return PG_DB.query_one?(request, plid, vid, as: Int64)
|
||||||
end
|
end
|
||||||
@ -244,7 +244,7 @@ module Invidious::Database::PlaylistVideos
|
|||||||
WHERE plid = $1
|
WHERE plid = $1
|
||||||
ORDER BY array_position($2, index)
|
ORDER BY array_position($2, index)
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_one?(request, plid, index, as: String)
|
return PG_DB.query_one?(request, plid, index, as: String)
|
||||||
end
|
end
|
||||||
@ -255,7 +255,7 @@ module Invidious::Database::PlaylistVideos
|
|||||||
WHERE plid = $1
|
WHERE plid = $1
|
||||||
ORDER BY array_position($2, index)
|
ORDER BY array_position($2, index)
|
||||||
LIMIT $3
|
LIMIT $3
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_all(request, plid, index, limit, as: String)
|
return PG_DB.query_all(request, plid, index, limit, as: String)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -11,7 +11,7 @@ module Invidious::Database::SessionIDs
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
INSERT INTO session_ids
|
INSERT INTO session_ids
|
||||||
VALUES ($1, $2, now())
|
VALUES ($1, $2, now())
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
request += " ON CONFLICT (id) DO NOTHING" if handle_conflicts
|
request += " ON CONFLICT (id) DO NOTHING" if handle_conflicts
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ module Invidious::Database::SessionIDs
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
DELETE FROM session_ids *
|
DELETE FROM session_ids *
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, sid)
|
PG_DB.exec(request, sid)
|
||||||
end
|
end
|
||||||
@ -35,7 +35,7 @@ module Invidious::Database::SessionIDs
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
DELETE FROM session_ids *
|
DELETE FROM session_ids *
|
||||||
WHERE email = $1
|
WHERE email = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, email)
|
PG_DB.exec(request, email)
|
||||||
end
|
end
|
||||||
@ -44,7 +44,7 @@ module Invidious::Database::SessionIDs
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
DELETE FROM session_ids *
|
DELETE FROM session_ids *
|
||||||
WHERE id = $1 AND email = $2
|
WHERE id = $1 AND email = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, sid, email)
|
PG_DB.exec(request, sid, email)
|
||||||
end
|
end
|
||||||
@ -57,7 +57,7 @@ module Invidious::Database::SessionIDs
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT email FROM session_ids
|
SELECT email FROM session_ids
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.query_one?(request, sid, as: String)
|
PG_DB.query_one?(request, sid, as: String)
|
||||||
end
|
end
|
||||||
@ -67,7 +67,7 @@ module Invidious::Database::SessionIDs
|
|||||||
SELECT id, issued FROM session_ids
|
SELECT id, issued FROM session_ids
|
||||||
WHERE email = $1
|
WHERE email = $1
|
||||||
ORDER BY issued DESC
|
ORDER BY issued DESC
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.query_all(request, email, as: {session: String, issued: Time})
|
PG_DB.query_all(request, email, as: {session: String, issued: Time})
|
||||||
end
|
end
|
||||||
|
|||||||
@ -10,7 +10,7 @@ module Invidious::Database::Statistics
|
|||||||
def count_users_total : Int64
|
def count_users_total : Int64
|
||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT count(*) FROM users
|
SELECT count(*) FROM users
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.query_one(request, as: Int64)
|
PG_DB.query_one(request, as: Int64)
|
||||||
end
|
end
|
||||||
@ -19,7 +19,7 @@ module Invidious::Database::Statistics
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT count(*) FROM users
|
SELECT count(*) FROM users
|
||||||
WHERE CURRENT_TIMESTAMP - updated < '6 months'
|
WHERE CURRENT_TIMESTAMP - updated < '6 months'
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.query_one(request, as: Int64)
|
PG_DB.query_one(request, as: Int64)
|
||||||
end
|
end
|
||||||
@ -28,7 +28,7 @@ module Invidious::Database::Statistics
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT count(*) FROM users
|
SELECT count(*) FROM users
|
||||||
WHERE CURRENT_TIMESTAMP - updated < '1 month'
|
WHERE CURRENT_TIMESTAMP - updated < '1 month'
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.query_one(request, as: Int64)
|
PG_DB.query_one(request, as: Int64)
|
||||||
end
|
end
|
||||||
@ -42,7 +42,7 @@ module Invidious::Database::Statistics
|
|||||||
SELECT updated FROM channels
|
SELECT updated FROM channels
|
||||||
ORDER BY updated DESC
|
ORDER BY updated DESC
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.query_one?(request, as: Time)
|
PG_DB.query_one?(request, as: Time)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -14,13 +14,13 @@ module Invidious::Database::Users
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
INSERT INTO users
|
INSERT INTO users
|
||||||
VALUES (#{arg_array(user_array)})
|
VALUES (#{arg_array(user_array)})
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
if update_on_conflict
|
if update_on_conflict
|
||||||
request += <<-SQL
|
request += <<-SQL
|
||||||
ON CONFLICT (email) DO UPDATE
|
ON CONFLICT (email) DO UPDATE
|
||||||
SET updated = $1, subscriptions = $3
|
SET updated = $1, subscriptions = $3
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
|
|
||||||
PG_DB.exec(request, args: user_array)
|
PG_DB.exec(request, args: user_array)
|
||||||
@ -30,7 +30,7 @@ module Invidious::Database::Users
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
DELETE FROM users *
|
DELETE FROM users *
|
||||||
WHERE email = $1
|
WHERE email = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, user.email)
|
PG_DB.exec(request, user.email)
|
||||||
end
|
end
|
||||||
@ -44,7 +44,7 @@ module Invidious::Database::Users
|
|||||||
UPDATE users
|
UPDATE users
|
||||||
SET watched = $1
|
SET watched = $1
|
||||||
WHERE email = $2
|
WHERE email = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, user.watched, user.email)
|
PG_DB.exec(request, user.watched, user.email)
|
||||||
end
|
end
|
||||||
@ -54,7 +54,7 @@ module Invidious::Database::Users
|
|||||||
UPDATE users
|
UPDATE users
|
||||||
SET watched = array_append(array_remove(watched, $1), $1)
|
SET watched = array_append(array_remove(watched, $1), $1)
|
||||||
WHERE email = $2
|
WHERE email = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, vid, user.email)
|
PG_DB.exec(request, vid, user.email)
|
||||||
end
|
end
|
||||||
@ -64,7 +64,7 @@ module Invidious::Database::Users
|
|||||||
UPDATE users
|
UPDATE users
|
||||||
SET watched = array_remove(watched, $1)
|
SET watched = array_remove(watched, $1)
|
||||||
WHERE email = $2
|
WHERE email = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, vid, user.email)
|
PG_DB.exec(request, vid, user.email)
|
||||||
end
|
end
|
||||||
@ -74,7 +74,7 @@ module Invidious::Database::Users
|
|||||||
UPDATE users
|
UPDATE users
|
||||||
SET watched = '{}'
|
SET watched = '{}'
|
||||||
WHERE email = $1
|
WHERE email = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, user.email)
|
PG_DB.exec(request, user.email)
|
||||||
end
|
end
|
||||||
@ -88,7 +88,7 @@ module Invidious::Database::Users
|
|||||||
UPDATE users
|
UPDATE users
|
||||||
SET feed_needs_update = true, subscriptions = $1
|
SET feed_needs_update = true, subscriptions = $1
|
||||||
WHERE email = $2
|
WHERE email = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, user.subscriptions, user.email)
|
PG_DB.exec(request, user.subscriptions, user.email)
|
||||||
end
|
end
|
||||||
@ -99,7 +99,7 @@ module Invidious::Database::Users
|
|||||||
SET feed_needs_update = true,
|
SET feed_needs_update = true,
|
||||||
subscriptions = array_append(subscriptions,$1)
|
subscriptions = array_append(subscriptions,$1)
|
||||||
WHERE email = $2
|
WHERE email = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, ucid, user.email)
|
PG_DB.exec(request, ucid, user.email)
|
||||||
end
|
end
|
||||||
@ -110,7 +110,7 @@ module Invidious::Database::Users
|
|||||||
SET feed_needs_update = true,
|
SET feed_needs_update = true,
|
||||||
subscriptions = array_remove(subscriptions, $1)
|
subscriptions = array_remove(subscriptions, $1)
|
||||||
WHERE email = $2
|
WHERE email = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, ucid, user.email)
|
PG_DB.exec(request, ucid, user.email)
|
||||||
end
|
end
|
||||||
@ -125,7 +125,7 @@ module Invidious::Database::Users
|
|||||||
SET notifications = array_cat(notifications, $1),
|
SET notifications = array_cat(notifications, $1),
|
||||||
feed_needs_update = true
|
feed_needs_update = true
|
||||||
WHERE $2 = ANY(subscriptions)
|
WHERE $2 = ANY(subscriptions)
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, video_ids, channel_id)
|
PG_DB.exec(request, video_ids, channel_id)
|
||||||
end
|
end
|
||||||
@ -135,7 +135,7 @@ module Invidious::Database::Users
|
|||||||
UPDATE users
|
UPDATE users
|
||||||
SET notifications = array_remove(notifications, $1)
|
SET notifications = array_remove(notifications, $1)
|
||||||
WHERE email = $2
|
WHERE email = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, vid, user.email)
|
PG_DB.exec(request, vid, user.email)
|
||||||
end
|
end
|
||||||
@ -145,7 +145,7 @@ module Invidious::Database::Users
|
|||||||
UPDATE users
|
UPDATE users
|
||||||
SET notifications = '{}', updated = now()
|
SET notifications = '{}', updated = now()
|
||||||
WHERE email = $1
|
WHERE email = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, user.email)
|
PG_DB.exec(request, user.email)
|
||||||
end
|
end
|
||||||
@ -159,7 +159,7 @@ module Invidious::Database::Users
|
|||||||
UPDATE users
|
UPDATE users
|
||||||
SET feed_needs_update = true
|
SET feed_needs_update = true
|
||||||
WHERE $1 = ANY(subscriptions)
|
WHERE $1 = ANY(subscriptions)
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, channel_id)
|
PG_DB.exec(request, channel_id)
|
||||||
end
|
end
|
||||||
@ -169,7 +169,7 @@ module Invidious::Database::Users
|
|||||||
UPDATE users
|
UPDATE users
|
||||||
SET preferences = $1
|
SET preferences = $1
|
||||||
WHERE email = $2
|
WHERE email = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, user.preferences.to_json, user.email)
|
PG_DB.exec(request, user.preferences.to_json, user.email)
|
||||||
end
|
end
|
||||||
@ -179,7 +179,7 @@ module Invidious::Database::Users
|
|||||||
UPDATE users
|
UPDATE users
|
||||||
SET password = $1
|
SET password = $1
|
||||||
WHERE email = $2
|
WHERE email = $2
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, pass, user.email)
|
PG_DB.exec(request, pass, user.email)
|
||||||
end
|
end
|
||||||
@ -192,7 +192,7 @@ module Invidious::Database::Users
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT * FROM users
|
SELECT * FROM users
|
||||||
WHERE email = $1
|
WHERE email = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_one?(request, email, as: User)
|
return PG_DB.query_one?(request, email, as: User)
|
||||||
end
|
end
|
||||||
@ -202,7 +202,7 @@ module Invidious::Database::Users
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT * FROM users
|
SELECT * FROM users
|
||||||
WHERE email = $1
|
WHERE email = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_one(request, email, as: User)
|
return PG_DB.query_one(request, email, as: User)
|
||||||
end
|
end
|
||||||
@ -211,7 +211,7 @@ module Invidious::Database::Users
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT * FROM users
|
SELECT * FROM users
|
||||||
WHERE token = $1
|
WHERE token = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_one?(request, token, as: User)
|
return PG_DB.query_one?(request, token, as: User)
|
||||||
end
|
end
|
||||||
@ -221,7 +221,7 @@ module Invidious::Database::Users
|
|||||||
SELECT notifications
|
SELECT notifications
|
||||||
FROM users
|
FROM users
|
||||||
WHERE email = $1
|
WHERE email = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_one(request, user.email, as: Array(String))
|
return PG_DB.query_one(request, user.email, as: Array(String))
|
||||||
end
|
end
|
||||||
|
|||||||
@ -8,7 +8,7 @@ module Invidious::Database::Videos
|
|||||||
INSERT INTO videos
|
INSERT INTO videos
|
||||||
VALUES ($1, $2, $3)
|
VALUES ($1, $2, $3)
|
||||||
ON CONFLICT (id) DO NOTHING
|
ON CONFLICT (id) DO NOTHING
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, video.id, video.info.to_json, video.updated)
|
PG_DB.exec(request, video.id, video.info.to_json, video.updated)
|
||||||
end
|
end
|
||||||
@ -17,7 +17,7 @@ module Invidious::Database::Videos
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
DELETE FROM videos *
|
DELETE FROM videos *
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, id)
|
PG_DB.exec(request, id)
|
||||||
end
|
end
|
||||||
@ -26,7 +26,7 @@ module Invidious::Database::Videos
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
DELETE FROM videos *
|
DELETE FROM videos *
|
||||||
WHERE updated < (now() - interval '6 hours')
|
WHERE updated < (now() - interval '6 hours')
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request)
|
PG_DB.exec(request)
|
||||||
end
|
end
|
||||||
@ -36,7 +36,7 @@ module Invidious::Database::Videos
|
|||||||
UPDATE videos
|
UPDATE videos
|
||||||
SET (id, info, updated) = ($1, $2, $3)
|
SET (id, info, updated) = ($1, $2, $3)
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
PG_DB.exec(request, video.id, video.info.to_json, video.updated)
|
PG_DB.exec(request, video.id, video.info.to_json, video.updated)
|
||||||
end
|
end
|
||||||
@ -45,7 +45,7 @@ module Invidious::Database::Videos
|
|||||||
request = <<-SQL
|
request = <<-SQL
|
||||||
SELECT * FROM videos
|
SELECT * FROM videos
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
return PG_DB.query_one?(request, id, as: Video)
|
return PG_DB.query_one?(request, id, as: Video)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -16,33 +16,33 @@ module Invidious::Frontend::Comments
|
|||||||
|
|
||||||
if child.depth > 0
|
if child.depth > 0
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
<div class="pure-g">
|
<div class="pure-g">
|
||||||
<div class="pure-u-1-24">
|
<div class="pure-u-1-24">
|
||||||
</div>
|
</div>
|
||||||
<div class="pure-u-23-24">
|
<div class="pure-u-23-24">
|
||||||
END_HTML
|
END_HTML
|
||||||
else
|
else
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
<div class="pure-g">
|
<div class="pure-g">
|
||||||
<div class="pure-u-1">
|
<div class="pure-u-1">
|
||||||
END_HTML
|
END_HTML
|
||||||
end
|
end
|
||||||
|
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
<p>
|
<p>
|
||||||
<a href="javascript:void(0)" data-onclick="toggle_parent">[ − ]</a>
|
<a href="javascript:void(0)" data-onclick="toggle_parent">[ − ]</a>
|
||||||
<b><a href="https://www.reddit.com/user/#{child.author}">#{child.author}</a></b>
|
<b><a href="https://www.reddit.com/user/#{child.author}">#{child.author}</a></b>
|
||||||
#{I18n.translate_count(locale, "comments_points_count", child.score, I18n::NumberFormatting::Separator)}
|
#{I18n.translate_count(locale, "comments_points_count", child.score, I18n::NumberFormatting::Separator)}
|
||||||
<span title="#{child.created_utc.to_s("%a %B %-d %T %Y UTC")}">#{I18n.translate(locale, "`x` ago", recode_date(child.created_utc, locale))}</span>
|
<span title="#{child.created_utc.to_s("%a %B %-d %T %Y UTC")}">#{I18n.translate(locale, "`x` ago", recode_date(child.created_utc, locale))}</span>
|
||||||
<a href="https://www.reddit.com#{child.permalink}" title="#{I18n.translate(locale, "permalink")}">#{I18n.translate(locale, "permalink")}</a>
|
<a href="https://www.reddit.com#{child.permalink}" title="#{I18n.translate(locale, "permalink")}">#{I18n.translate(locale, "permalink")}</a>
|
||||||
</p>
|
</p>
|
||||||
<div>
|
<div>
|
||||||
#{body_html}
|
#{body_html}
|
||||||
#{replies_html}
|
#{replies_html}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
END_HTML
|
END_HTML
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -13,16 +13,16 @@ module Invidious::Frontend::Comments
|
|||||||
)
|
)
|
||||||
|
|
||||||
replies_html = <<-END_HTML
|
replies_html = <<-END_HTML
|
||||||
<div id="replies" class="pure-g">
|
<div id="replies" class="pure-g">
|
||||||
<div class="pure-u-1-24"></div>
|
<div class="pure-u-1-24"></div>
|
||||||
<div class="pure-u-23-24">
|
<div class="pure-u-23-24">
|
||||||
<p>
|
<p>
|
||||||
<a href="javascript:void(0)" data-continuation="#{child["replies"]["continuation"]}"
|
<a href="javascript:void(0)" data-continuation="#{child["replies"]["continuation"]}"
|
||||||
data-onclick="get_youtube_replies" data-load-replies>#{replies_count_text}</a>
|
data-onclick="get_youtube_replies" data-load-replies>#{replies_count_text}</a>
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
END_HTML
|
||||||
END_HTML
|
|
||||||
elsif comments["authorId"]? && !comments["singlePost"]?
|
elsif comments["authorId"]? && !comments["singlePost"]?
|
||||||
# for posts we should display a link to the post
|
# for posts we should display a link to the post
|
||||||
replies_count_text = I18n.translate_count(locale,
|
replies_count_text = I18n.translate_count(locale,
|
||||||
@ -32,15 +32,15 @@ module Invidious::Frontend::Comments
|
|||||||
)
|
)
|
||||||
|
|
||||||
replies_html = <<-END_HTML
|
replies_html = <<-END_HTML
|
||||||
<div class="pure-g">
|
<div class="pure-g">
|
||||||
<div class="pure-u-1-24"></div>
|
<div class="pure-u-1-24"></div>
|
||||||
<div class="pure-u-23-24">
|
<div class="pure-u-23-24">
|
||||||
<p>
|
<p>
|
||||||
<a href="/post/#{child["commentId"]}?ucid=#{comments["authorId"]}">#{replies_count_text}</a>
|
<a href="/post/#{child["commentId"]}?ucid=#{comments["authorId"]}">#{replies_count_text}</a>
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
END_HTML
|
||||||
END_HTML
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if !thin_mode
|
if !thin_mode
|
||||||
@ -70,18 +70,18 @@ module Invidious::Frontend::Comments
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
<div class="pure-g" style="width:100%">
|
<div class="pure-g" style="width:100%">
|
||||||
<div class="channel-profile pure-u-4-24 pure-u-md-2-24">
|
<div class="channel-profile pure-u-4-24 pure-u-md-2-24">
|
||||||
<img loading="lazy" style="margin-right:1em;margin-top:1em;width:90%" src="#{author_thumbnail}" alt="" />
|
<img loading="lazy" style="margin-right:1em;margin-top:1em;width:90%" src="#{author_thumbnail}" alt="" />
|
||||||
</div>
|
</div>
|
||||||
<div class="pure-u-20-24 pure-u-md-22-24">
|
<div class="pure-u-20-24 pure-u-md-22-24">
|
||||||
<p>
|
<p>
|
||||||
<b>
|
<b>
|
||||||
<a class="#{child["authorIsChannelOwner"] == true ? "channel-owner" : ""}" href="#{child["authorUrl"]}">#{author_name}</a>
|
<a class="#{child["authorIsChannelOwner"] == true ? "channel-owner" : ""}" href="#{child["authorUrl"]}">#{author_name}</a>
|
||||||
</b>
|
</b>
|
||||||
#{sponsor_icon}
|
#{sponsor_icon}
|
||||||
<p style="white-space:pre-wrap">#{child["contentHtml"]}</p>
|
<p style="white-space:pre-wrap">#{child["contentHtml"]}</p>
|
||||||
END_HTML
|
END_HTML
|
||||||
|
|
||||||
if child["attachment"]?
|
if child["attachment"]?
|
||||||
attachment = child["attachment"]
|
attachment = child["attachment"]
|
||||||
@ -91,25 +91,25 @@ module Invidious::Frontend::Comments
|
|||||||
attachment = attachment["imageThumbnails"][1]
|
attachment = attachment["imageThumbnails"][1]
|
||||||
|
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
<div class="pure-g">
|
<div class="pure-g">
|
||||||
<div class="pure-u-1 pure-u-md-1-2">
|
<div class="pure-u-1 pure-u-md-1-2">
|
||||||
<img loading="lazy" style="width:100%" src="/ggpht#{URI.parse(attachment["url"].as_s).request_target}" alt="" />
|
<img loading="lazy" style="width:100%" src="/ggpht#{URI.parse(attachment["url"].as_s).request_target}" alt="" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
END_HTML
|
||||||
END_HTML
|
|
||||||
when "video"
|
when "video"
|
||||||
if attachment["error"]?
|
if attachment["error"]?
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
<div class="pure-g video-iframe-wrapper">
|
<div class="pure-g video-iframe-wrapper">
|
||||||
<p>#{attachment["error"]}</p>
|
<p>#{attachment["error"]}</p>
|
||||||
</div>
|
</div>
|
||||||
END_HTML
|
END_HTML
|
||||||
else
|
else
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
<div class="pure-g video-iframe-wrapper">
|
<div class="pure-g video-iframe-wrapper">
|
||||||
<iframe class="video-iframe" src='/embed/#{attachment["videoId"]?}?autoplay=0'></iframe>
|
<iframe class="video-iframe" src='/embed/#{attachment["videoId"]?}?autoplay=0'></iframe>
|
||||||
</div>
|
</div>
|
||||||
END_HTML
|
END_HTML
|
||||||
end
|
end
|
||||||
when "multiImage"
|
when "multiImage"
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
@ -137,35 +137,34 @@ module Invidious::Frontend::Comments
|
|||||||
END_HTML
|
END_HTML
|
||||||
end
|
end
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
</div>
|
</div>
|
||||||
<div id="skip-#{child["commentId"]}"></div>
|
<div id="skip-#{child["commentId"]}"></div>
|
||||||
</section>
|
</section>
|
||||||
END_HTML
|
END_HTML
|
||||||
else nil # Ignore
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
<p>
|
<p>
|
||||||
<span title="#{Time.unix(child["published"].as_i64).to_s(I18n.translate(locale, "%A %B %-d, %Y"))}">#{I18n.translate(locale, "`x` ago", recode_date(Time.unix(child["published"].as_i64), locale))} #{child["isEdited"] == true ? I18n.translate(locale, "(edited)") : ""}</span>
|
<span title="#{Time.unix(child["published"].as_i64).to_s(I18n.translate(locale, "%A %B %-d, %Y"))}">#{I18n.translate(locale, "`x` ago", recode_date(Time.unix(child["published"].as_i64), locale))} #{child["isEdited"] == true ? I18n.translate(locale, "(edited)") : ""}</span>
|
||||||
|
|
|
|
||||||
END_HTML
|
END_HTML
|
||||||
|
|
||||||
if comments["videoId"]?
|
if comments["videoId"]?
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
<a rel="noreferrer noopener" href="https://www.youtube.com/watch?v=#{comments["videoId"]}&lc=#{child["commentId"]}" title="#{I18n.translate(locale, "YouTube comment permalink")}">[YT]</a>
|
<a rel="noreferrer noopener" href="https://www.youtube.com/watch?v=#{comments["videoId"]}&lc=#{child["commentId"]}" title="#{I18n.translate(locale, "YouTube comment permalink")}">[YT]</a>
|
||||||
|
|
|
|
||||||
END_HTML
|
END_HTML
|
||||||
elsif comments["authorId"]?
|
elsif comments["authorId"]?
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
<a rel="noreferrer noopener" href="https://www.youtube.com/channel/#{comments["authorId"]}/community?lb=#{child["commentId"]}" title="#{I18n.translate(locale, "YouTube comment permalink")}">[YT]</a>
|
<a rel="noreferrer noopener" href="https://www.youtube.com/channel/#{comments["authorId"]}/community?lb=#{child["commentId"]}" title="#{I18n.translate(locale, "YouTube comment permalink")}">[YT]</a>
|
||||||
|
|
|
|
||||||
END_HTML
|
END_HTML
|
||||||
end
|
end
|
||||||
|
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
<i class="icon ion-ios-thumbs-up"></i> #{number_with_separator(child["likeCount"])}
|
<i class="icon ion-ios-thumbs-up"></i> #{number_with_separator(child["likeCount"])}
|
||||||
END_HTML
|
END_HTML
|
||||||
|
|
||||||
if child["creatorHeart"]?
|
if child["creatorHeart"]?
|
||||||
if !thin_mode
|
if !thin_mode
|
||||||
@ -184,28 +183,28 @@ module Invidious::Frontend::Comments
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
END_HTML
|
END_HTML
|
||||||
end
|
end
|
||||||
|
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
</p>
|
</p>
|
||||||
#{replies_html}
|
#{replies_html}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
END_HTML
|
||||||
END_HTML
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if comments["continuation"]?
|
if comments["continuation"]?
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
<div class="pure-g">
|
<div class="pure-g">
|
||||||
<div class="pure-u-1">
|
<div class="pure-u-1">
|
||||||
<p>
|
<p>
|
||||||
<a href="javascript:void(0)" data-continuation="#{comments["continuation"]}"
|
<a href="javascript:void(0)" data-continuation="#{comments["continuation"]}"
|
||||||
data-onclick="get_youtube_replies" data-load-more #{"data-load-replies" if is_replies}>#{I18n.translate(locale, "Load more")}</a>
|
data-onclick="get_youtube_replies" data-load-more #{"data-load-replies" if is_replies}>#{I18n.translate(locale, "Load more")}</a>
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
END_HTML
|
||||||
END_HTML
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -41,11 +41,11 @@ module Invidious::Frontend::SearchFilters
|
|||||||
str << "\t\t\t\t<div class=\"filter-column\"><fieldset>\n"
|
str << "\t\t\t\t<div class=\"filter-column\"><fieldset>\n"
|
||||||
|
|
||||||
str << "\t\t\t\t\t<legend><div class=\"filter-name underlined\">"
|
str << "\t\t\t\t\t<legend><div class=\"filter-name underlined\">"
|
||||||
str << I18n.translate(locale, "search_filters_{{name}}_label")
|
str << I18n.translate(locale, "search_filters_{{ name }}_label")
|
||||||
str << "</div></legend>\n"
|
str << "</div></legend>\n"
|
||||||
|
|
||||||
str << "\t\t\t\t\t<div class=\"filter-options\">\n"
|
str << "\t\t\t\t\t<div class=\"filter-options\">\n"
|
||||||
make_{{name}}_filter_options(str, filters.{{name}}, locale)
|
make_{{ name }}_filter_options(str, filters.{{ name }}, locale)
|
||||||
str << "\t\t\t\t\t</div>"
|
str << "\t\t\t\t\t</div>"
|
||||||
|
|
||||||
str << "\t\t\t\t</fieldset></div>\n"
|
str << "\t\t\t\t</fieldset></div>\n"
|
||||||
@ -57,12 +57,12 @@ module Invidious::Frontend::SearchFilters
|
|||||||
{% date = value.underscore %}
|
{% date = value.underscore %}
|
||||||
|
|
||||||
str << "\t\t\t\t\t\t<div>"
|
str << "\t\t\t\t\t\t<div>"
|
||||||
str << "<input type='radio' name='date' id='filter-date-{{date}}' value='{{date}}'"
|
str << "<input type='radio' name='date' id='filter-date-{{ date }}' value='{{ date }}'"
|
||||||
str << " checked" if value.{{date}}?
|
str << " checked" if value.{{ date }}?
|
||||||
str << '>'
|
str << '>'
|
||||||
|
|
||||||
str << "<label for='filter-date-{{date}}'>"
|
str << "<label for='filter-date-{{ date }}'>"
|
||||||
str << I18n.translate(locale, "search_filters_date_option_{{date}}")
|
str << I18n.translate(locale, "search_filters_date_option_{{ date }}")
|
||||||
str << "</label></div>\n"
|
str << "</label></div>\n"
|
||||||
{% end %}
|
{% end %}
|
||||||
end
|
end
|
||||||
@ -73,12 +73,12 @@ module Invidious::Frontend::SearchFilters
|
|||||||
{% type = value.underscore %}
|
{% type = value.underscore %}
|
||||||
|
|
||||||
str << "\t\t\t\t\t\t<div>"
|
str << "\t\t\t\t\t\t<div>"
|
||||||
str << "<input type='radio' name='type' id='filter-type-{{type}}' value='{{type}}'"
|
str << "<input type='radio' name='type' id='filter-type-{{ type }}' value='{{ type }}'"
|
||||||
str << " checked" if value.{{type}}?
|
str << " checked" if value.{{ type }}?
|
||||||
str << '>'
|
str << '>'
|
||||||
|
|
||||||
str << "<label for='filter-type-{{type}}'>"
|
str << "<label for='filter-type-{{ type }}'>"
|
||||||
str << I18n.translate(locale, "search_filters_type_option_{{type}}")
|
str << I18n.translate(locale, "search_filters_type_option_{{ type }}")
|
||||||
str << "</label></div>\n"
|
str << "</label></div>\n"
|
||||||
{% end %}
|
{% end %}
|
||||||
end
|
end
|
||||||
@ -89,12 +89,12 @@ module Invidious::Frontend::SearchFilters
|
|||||||
{% duration = value.underscore %}
|
{% duration = value.underscore %}
|
||||||
|
|
||||||
str << "\t\t\t\t\t\t<div>"
|
str << "\t\t\t\t\t\t<div>"
|
||||||
str << "<input type='radio' name='duration' id='filter-duration-{{duration}}' value='{{duration}}'"
|
str << "<input type='radio' name='duration' id='filter-duration-{{ duration }}' value='{{ duration }}'"
|
||||||
str << " checked" if value.{{duration}}?
|
str << " checked" if value.{{ duration }}?
|
||||||
str << '>'
|
str << '>'
|
||||||
|
|
||||||
str << "<label for='filter-duration-{{duration}}'>"
|
str << "<label for='filter-duration-{{ duration }}'>"
|
||||||
str << I18n.translate(locale, "search_filters_duration_option_{{duration}}")
|
str << I18n.translate(locale, "search_filters_duration_option_{{ duration }}")
|
||||||
str << "</label></div>\n"
|
str << "</label></div>\n"
|
||||||
{% end %}
|
{% end %}
|
||||||
end
|
end
|
||||||
@ -106,12 +106,12 @@ module Invidious::Frontend::SearchFilters
|
|||||||
{% feature = value.underscore %}
|
{% feature = value.underscore %}
|
||||||
|
|
||||||
str << "\t\t\t\t\t\t<div>"
|
str << "\t\t\t\t\t\t<div>"
|
||||||
str << "<input type='checkbox' name='features' id='filter-feature-{{feature}}' value='{{feature}}'"
|
str << "<input type='checkbox' name='features' id='filter-feature-{{ feature }}' value='{{ feature }}'"
|
||||||
str << " checked" if value.{{feature}}?
|
str << " checked" if value.{{ feature }}?
|
||||||
str << '>'
|
str << '>'
|
||||||
|
|
||||||
str << "<label for='filter-feature-{{feature}}'>"
|
str << "<label for='filter-feature-{{ feature }}'>"
|
||||||
str << I18n.translate(locale, "search_filters_features_option_{{feature}}")
|
str << I18n.translate(locale, "search_filters_features_option_{{ feature }}")
|
||||||
str << "</label></div>\n"
|
str << "</label></div>\n"
|
||||||
{% end %}
|
{% end %}
|
||||||
{% end %}
|
{% end %}
|
||||||
@ -123,12 +123,12 @@ module Invidious::Frontend::SearchFilters
|
|||||||
{% sort = value.underscore %}
|
{% sort = value.underscore %}
|
||||||
|
|
||||||
str << "\t\t\t\t\t\t<div>"
|
str << "\t\t\t\t\t\t<div>"
|
||||||
str << "<input type='radio' name='sort' id='filter-sort-{{sort}}' value='{{sort}}'"
|
str << "<input type='radio' name='sort' id='filter-sort-{{ sort }}' value='{{ sort }}'"
|
||||||
str << " checked" if value.{{sort}}?
|
str << " checked" if value.{{ sort }}?
|
||||||
str << '>'
|
str << '>'
|
||||||
|
|
||||||
str << "<label for='filter-sort-{{sort}}'>"
|
str << "<label for='filter-sort-{{ sort }}'>"
|
||||||
str << I18n.translate(locale, "search_filters_sort_option_{{sort}}")
|
str << I18n.translate(locale, "search_filters_sort_option_{{ sort }}")
|
||||||
str << "</label></div>\n"
|
str << "</label></div>\n"
|
||||||
{% end %}
|
{% end %}
|
||||||
end
|
end
|
||||||
|
|||||||
@ -68,7 +68,7 @@ class HTTP::Server::Response
|
|||||||
class Output
|
class Output
|
||||||
private def unbuffered_flush
|
private def unbuffered_flush
|
||||||
@io.flush
|
@io.flush
|
||||||
rescue ex : IO::Error
|
rescue IO::Error
|
||||||
unbuffered_close
|
unbuffered_close
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
# -------------------
|
# -------------------
|
||||||
|
|
||||||
macro error_template(*args)
|
macro error_template(*args)
|
||||||
error_template_helper(env, {{args.splat}})
|
error_template_helper(env, {{ args.splat }})
|
||||||
end
|
end
|
||||||
|
|
||||||
def github_details(summary : String, content : String)
|
def github_details(summary : String, content : String)
|
||||||
@ -22,12 +22,12 @@ def get_issue_template(env : HTTP::Server::Context, exception : Exception) : Tup
|
|||||||
issue_title = "#{exception.message} (#{exception.class})"
|
issue_title = "#{exception.message} (#{exception.class})"
|
||||||
|
|
||||||
issue_template = <<-TEXT
|
issue_template = <<-TEXT
|
||||||
Title: `#{HTML.escape(issue_title)}`
|
Title: `#{HTML.escape(issue_title)}`
|
||||||
Date: `#{Time::Format::ISO_8601_DATE_TIME.format(Time.utc)}`
|
Date: `#{Time::Format::ISO_8601_DATE_TIME.format(Time.utc)}`
|
||||||
Route: `#{HTML.escape(env.request.resource)}`
|
Route: `#{HTML.escape(env.request.resource)}`
|
||||||
Version: `#{SOFTWARE["version"]} @ #{SOFTWARE["branch"]}`
|
Version: `#{SOFTWARE["version"]} @ #{SOFTWARE["branch"]}`
|
||||||
|
|
||||||
TEXT
|
TEXT
|
||||||
|
|
||||||
issue_template += github_details("Backtrace", exception.inspect_with_backtrace)
|
issue_template += github_details("Backtrace", exception.inspect_with_backtrace)
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ def error_template_helper(env : HTTP::Server::Context, status_code : Int32, exce
|
|||||||
<!-- TODO: Add a "copy to clipboard" button -->
|
<!-- TODO: Add a "copy to clipboard" button -->
|
||||||
<pre class="error-issue-template">#{issue_template}</pre>
|
<pre class="error-issue-template">#{issue_template}</pre>
|
||||||
</div>
|
</div>
|
||||||
END_HTML
|
END_HTML
|
||||||
|
|
||||||
# Don't show the usual "next steps" widget. The same options are
|
# Don't show the usual "next steps" widget. The same options are
|
||||||
# proposed above the error message, just worded differently.
|
# proposed above the error message, just worded differently.
|
||||||
@ -106,7 +106,7 @@ end
|
|||||||
# -------------------
|
# -------------------
|
||||||
|
|
||||||
macro error_atom(*args)
|
macro error_atom(*args)
|
||||||
error_atom_helper(env, {{args.splat}})
|
error_atom_helper(env, {{ args.splat }})
|
||||||
end
|
end
|
||||||
|
|
||||||
def error_atom_helper(env : HTTP::Server::Context, status_code : Int32, exception : Exception)
|
def error_atom_helper(env : HTTP::Server::Context, status_code : Int32, exception : Exception)
|
||||||
@ -132,14 +132,14 @@ end
|
|||||||
# -------------------
|
# -------------------
|
||||||
|
|
||||||
macro error_json(*args)
|
macro error_json(*args)
|
||||||
error_json_helper(env, {{args.splat}})
|
error_json_helper(env, {{ args.splat }})
|
||||||
end
|
end
|
||||||
|
|
||||||
def error_json_helper(
|
def error_json_helper(
|
||||||
env : HTTP::Server::Context,
|
env : HTTP::Server::Context,
|
||||||
status_code : Int32,
|
status_code : Int32,
|
||||||
exception : Exception,
|
exception : Exception,
|
||||||
additional_fields : Hash(String, Object) | Nil = nil,
|
additional_fields : Hash(String, Object)? = nil,
|
||||||
)
|
)
|
||||||
if exception.is_a?(InfoException)
|
if exception.is_a?(InfoException)
|
||||||
return error_json_helper(env, status_code, exception.message || "", additional_fields)
|
return error_json_helper(env, status_code, exception.message || "", additional_fields)
|
||||||
@ -161,7 +161,7 @@ def error_json_helper(
|
|||||||
env : HTTP::Server::Context,
|
env : HTTP::Server::Context,
|
||||||
status_code : Int32,
|
status_code : Int32,
|
||||||
message : String,
|
message : String,
|
||||||
additional_fields : Hash(String, Object) | Nil = nil,
|
additional_fields : Hash(String, Object)? = nil,
|
||||||
)
|
)
|
||||||
env.response.content_type = "application/json"
|
env.response.content_type = "application/json"
|
||||||
env.response.status_code = status_code
|
env.response.status_code = status_code
|
||||||
@ -204,7 +204,7 @@ def error_redirect_helper(env : HTTP::Server::Context)
|
|||||||
<a rel="noreferrer noopener" href="https://www.youtube.com#{env.request.resource}">#{go_to_youtube}</a>
|
<a rel="noreferrer noopener" href="https://www.youtube.com#{env.request.resource}">#{go_to_youtube}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
END_HTML
|
END_HTML
|
||||||
else
|
else
|
||||||
return ""
|
return ""
|
||||||
end
|
end
|
||||||
|
|||||||
@ -2,10 +2,10 @@ module HTTP::Handler
|
|||||||
@@exclude_routes_tree = Radix::Tree(String).new
|
@@exclude_routes_tree = Radix::Tree(String).new
|
||||||
|
|
||||||
macro exclude(paths, method = "GET")
|
macro exclude(paths, method = "GET")
|
||||||
class_name = {{@type.name}}
|
class_name = {{ @type.name }}
|
||||||
method_downcase = {{method.downcase}}
|
method_downcase = {{ method.downcase }}
|
||||||
class_name_method = "#{class_name}/#{method_downcase}"
|
class_name_method = "#{class_name}/#{method_downcase}"
|
||||||
({{paths}}).each do |path|
|
({{ paths }}).each do |path|
|
||||||
@@exclude_routes_tree.add class_name_method + path, '/' + method_downcase + path
|
@@exclude_routes_tree.add class_name_method + path, '/' + method_downcase + path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -20,8 +20,8 @@ module HTTP::Handler
|
|||||||
end
|
end
|
||||||
|
|
||||||
class Kemal::RouteHandler
|
class Kemal::RouteHandler
|
||||||
{% for method in %w(GET POST PUT HEAD DELETE PATCH OPTIONS) %}
|
{% for method in %w[GET POST PUT HEAD DELETE PATCH OPTIONS] %}
|
||||||
exclude ["/api/v1/*"], {{method}}
|
exclude ["/api/v1/*"], {{ method }}
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
# Processes the route if it's a match. Otherwise renders 404.
|
# Processes the route if it's a match. Otherwise renders 404.
|
||||||
@ -44,8 +44,8 @@ class Kemal::RouteHandler
|
|||||||
end
|
end
|
||||||
|
|
||||||
class Kemal::ExceptionHandler
|
class Kemal::ExceptionHandler
|
||||||
{% for method in %w(GET POST PUT HEAD DELETE PATCH OPTIONS) %}
|
{% for method in %w[GET POST PUT HEAD DELETE PATCH OPTIONS] %}
|
||||||
exclude ["/api/v1/*"], {{method}}
|
exclude ["/api/v1/*"], {{ method }}
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
private def call_exception_with_status_code(context : HTTP::Server::Context, exception : Exception, status_code : Int32)
|
private def call_exception_with_status_code(context : HTTP::Server::Context, exception : Exception, status_code : Int32)
|
||||||
@ -72,8 +72,8 @@ class FilteredCompressHandler < HTTP::CompressHandler
|
|||||||
end
|
end
|
||||||
|
|
||||||
class AuthHandler < Kemal::Handler
|
class AuthHandler < Kemal::Handler
|
||||||
{% for method in %w(GET POST PUT HEAD DELETE PATCH OPTIONS) %}
|
{% for method in %w[GET POST PUT HEAD DELETE PATCH OPTIONS] %}
|
||||||
only ["/api/v1/auth/*"], {{method}}
|
only ["/api/v1/auth/*"], {{ method }}
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
@ -121,8 +121,8 @@ class AuthHandler < Kemal::Handler
|
|||||||
end
|
end
|
||||||
|
|
||||||
class APIHandler < Kemal::Handler
|
class APIHandler < Kemal::Handler
|
||||||
{% for method in %w(GET POST PUT HEAD DELETE PATCH OPTIONS) %}
|
{% for method in %w[GET POST PUT HEAD DELETE PATCH OPTIONS] %}
|
||||||
only ["/api/v1/*"], {{method}}
|
only ["/api/v1/*"], {{ method }}
|
||||||
{% end %}
|
{% end %}
|
||||||
exclude ["/api/v1/auth/notifications"], "GET"
|
exclude ["/api/v1/auth/notifications"], "GET"
|
||||||
exclude ["/api/v1/auth/notifications"], "POST"
|
exclude ["/api/v1/auth/notifications"], "POST"
|
||||||
@ -134,9 +134,9 @@ class APIHandler < Kemal::Handler
|
|||||||
end
|
end
|
||||||
|
|
||||||
class DisableAbusableAPIHandler < Kemal::Handler
|
class DisableAbusableAPIHandler < Kemal::Handler
|
||||||
{% for method in %w(GET HEAD) %}
|
{% for method in %w[GET HEAD] %}
|
||||||
# This endpoints make a video request to Invidious companion.
|
# This endpoints make a video request to Invidious companion.
|
||||||
{% for endpoint in %w(videos clips transcripts) %}
|
{% for endpoint in %w[videos clips transcripts] %}
|
||||||
only ["/api/v1/{{ endpoint.id }}/:id"], {{ method }}
|
only ["/api/v1/{{ endpoint.id }}/:id"], {{ method }}
|
||||||
{% end %}
|
{% end %}
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|||||||
@ -93,7 +93,7 @@ module Helpers
|
|||||||
sleep 1.minute
|
sleep 1.minute
|
||||||
Fiber.yield
|
Fiber.yield
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -149,7 +149,7 @@ module Helpers
|
|||||||
|
|
||||||
id += 1
|
id += 1
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
ensure
|
ensure
|
||||||
connection_channel.send({false, connection})
|
connection_channel.send({false, connection})
|
||||||
end
|
end
|
||||||
@ -163,7 +163,7 @@ module Helpers
|
|||||||
env.response.flush
|
env.response.flush
|
||||||
sleep (20 + rand(11)).seconds
|
sleep (20 + rand(11)).seconds
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
ensure
|
ensure
|
||||||
connection_channel.send({false, connection})
|
connection_channel.send({false, connection})
|
||||||
end
|
end
|
||||||
|
|||||||
@ -103,7 +103,7 @@ module I18n
|
|||||||
return locales
|
return locales
|
||||||
end
|
end
|
||||||
|
|
||||||
def translate(locale : String?, key : String, text : String | Hash(String, String) | Nil = nil) : String
|
def translate(locale : String?, key : String, text : String? | Hash(String, String)? = nil) : String
|
||||||
# Log a warning if "key" doesn't exist in en-US locale and return
|
# Log a warning if "key" doesn't exist in en-US locale and return
|
||||||
# that key as the text, so this is more or less transparent to the user.
|
# that key as the text, so this is more or less transparent to the user.
|
||||||
if !LOCALES["en-US"].has_key?(key)
|
if !LOCALES["en-US"].has_key?(key)
|
||||||
|
|||||||
@ -55,10 +55,10 @@ class Invidious::LogHandler < Kemal::BaseLogHandler
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
{% for level in %w(trace debug info warn error fatal) %}
|
{% for level in %w[trace debug info warn error fatal] %}
|
||||||
def {{level.id}}(message : String)
|
def {{ level.id }}(message : String)
|
||||||
if LogLevel::{{level.id.capitalize}} >= @level
|
if LogLevel::{{ level.id.capitalize }} >= @level
|
||||||
puts("#{Time.utc} [{{level.id}}] #{message}".colorize(color(LogLevel::{{level.id.capitalize}})))
|
puts("#{Time.utc} [{{ level.id }}] #{message}".colorize(color(LogLevel::{{ level.id.capitalize }})))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|||||||
@ -49,24 +49,24 @@ module JSON::Serializable
|
|||||||
end
|
end
|
||||||
|
|
||||||
macro templated(_filename, template = "template", navbar_search = true)
|
macro templated(_filename, template = "template", navbar_search = true)
|
||||||
navbar_search = {{navbar_search}}
|
navbar_search = {{ navbar_search }}
|
||||||
|
|
||||||
{{ filename = "src/invidious/views/" + _filename + ".ecr" }}
|
{{ filename = "src/invidious/views/" + _filename + ".ecr" }}
|
||||||
{{ layout = "src/invidious/views/" + template + ".ecr" }}
|
{{ layout = "src/invidious/views/" + template + ".ecr" }}
|
||||||
|
|
||||||
__content_filename__ = {{filename}}
|
__content_filename__ = {{ filename }}
|
||||||
render {{filename}}, {{layout}}
|
render {{ filename }}, {{ layout }}
|
||||||
end
|
end
|
||||||
|
|
||||||
macro rendered(filename)
|
macro rendered(filename)
|
||||||
render("src/invidious/views/#{{{filename}}}.ecr")
|
render("src/invidious/views/#{{{ filename }}}.ecr")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Similar to Kemals halt method but works in a
|
# Similar to Kemals halt method but works in a
|
||||||
# method.
|
# method.
|
||||||
macro haltf(env, status_code = 200, response = "")
|
macro haltf(env, status_code = 200, response = "")
|
||||||
{{env}}.response.status_code = {{status_code}}
|
{{ env }}.response.status_code = {{ status_code }}
|
||||||
{{env}}.response.print {{response}}
|
{{ env }}.response.print {{ response }}
|
||||||
{{env}}.response.close
|
{{ env }}.response.close
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|||||||
@ -116,7 +116,7 @@ def scope_includes_scope(scope, subset)
|
|||||||
subset_endpoint = subset_endpoint.downcase
|
subset_endpoint = subset_endpoint.downcase
|
||||||
|
|
||||||
if methods.empty?
|
if methods.empty?
|
||||||
methods = %w(GET POST PUT HEAD DELETE PATCH OPTIONS)
|
methods = %w[GET POST PUT HEAD DELETE PATCH OPTIONS]
|
||||||
end
|
end
|
||||||
|
|
||||||
if methods & subset_methods != subset_methods
|
if methods & subset_methods != subset_methods
|
||||||
|
|||||||
@ -102,7 +102,7 @@ def decode_date(string : String)
|
|||||||
# Try to parse as format Jul 10, 2000
|
# Try to parse as format Jul 10, 2000
|
||||||
begin
|
begin
|
||||||
return Time.parse(string, "%b %-d, %Y", Time::Location.local)
|
return Time.parse(string, "%b %-d, %Y", Time::Location.local)
|
||||||
rescue ex
|
rescue
|
||||||
end
|
end
|
||||||
|
|
||||||
case string
|
case string
|
||||||
@ -110,7 +110,6 @@ def decode_date(string : String)
|
|||||||
return Time.utc
|
return Time.utc
|
||||||
when "yesterday"
|
when "yesterday"
|
||||||
return Time.utc - 1.day
|
return Time.utc - 1.day
|
||||||
else nil # Continue
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# String matches format "20 hours ago", "4 months ago", "20s ago", "15min ago"...
|
# String matches format "20 hours ago", "4 months ago", "20s ago", "15min ago"...
|
||||||
@ -177,7 +176,7 @@ def short_text_to_number(short_text : String) : Int64
|
|||||||
end
|
end
|
||||||
|
|
||||||
return number.to_i64
|
return number.to_i64
|
||||||
rescue ex
|
rescue
|
||||||
return 0_i64
|
return 0_i64
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -106,7 +106,7 @@ module Invidious::HttpServer
|
|||||||
# Can be removed once https://github.com/crystal-lang/crystal/issues/15817 is fixed.
|
# Can be removed once https://github.com/crystal-lang/crystal/issues/15817 is fixed.
|
||||||
private def serve_file_range(context : HTTP::Server::Context, file : IO, range_header : String, file_info)
|
private def serve_file_range(context : HTTP::Server::Context, file : IO, range_header : String, file_info)
|
||||||
# Paste in the body of inherited serve_file_range
|
# Paste in the body of inherited serve_file_range
|
||||||
{{@type.superclass.methods.select(&.name.==("serve_file_range"))[0].body}}
|
{{ @type.superclass.methods.select(&.name.==("serve_file_range"))[0].body }}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Clear cached files.
|
# Clear cached files.
|
||||||
|
|||||||
@ -69,7 +69,7 @@ class Invidious::Jobs::InstanceListRefreshJob < Invidious::Jobs::BaseJob
|
|||||||
|
|
||||||
raw_instance_list = JSON.parse(instance_api_client.get("/instances.json").body).as_a
|
raw_instance_list = JSON.parse(instance_api_client.get("/instances.json").body).as_a
|
||||||
instance_api_client.close
|
instance_api_client.close
|
||||||
rescue ex : Socket::ConnectError | IO::TimeoutError | JSON::ParseException
|
rescue Socket::ConnectError | IO::TimeoutError | JSON::ParseException
|
||||||
raw_instance_list = [] of JSON::Any
|
raw_instance_list = [] of JSON::Any
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -138,7 +138,7 @@ module Invidious::JSONify::APIv1
|
|||||||
|
|
||||||
if fmt_info = Invidious::Videos::Formats.itag_to_metadata?(fmt["itag"])
|
if fmt_info = Invidious::Videos::Formats.itag_to_metadata?(fmt["itag"])
|
||||||
json.field "container", fmt_info["ext"]
|
json.field "container", fmt_info["ext"]
|
||||||
json.field "encoding", fmt_info["vcodec"]? || fmt_info["acodec"]
|
json.field("encoding", fmt_info["vcodec"]? || fmt_info["acodec"])
|
||||||
end
|
end
|
||||||
|
|
||||||
# Livestream chunk infos
|
# Livestream chunk infos
|
||||||
@ -198,8 +198,8 @@ module Invidious::JSONify::APIv1
|
|||||||
end
|
end
|
||||||
|
|
||||||
if fmt_info = Invidious::Videos::Formats.itag_to_metadata?(fmt["itag"])
|
if fmt_info = Invidious::Videos::Formats.itag_to_metadata?(fmt["itag"])
|
||||||
json.field "container", fmt_info["ext"]
|
json.field("container", fmt_info["ext"])
|
||||||
json.field "encoding", fmt_info["vcodec"]? || fmt_info["acodec"]
|
json.field("encoding", fmt_info["vcodec"]? || fmt_info["acodec"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -83,14 +83,14 @@ end
|
|||||||
|
|
||||||
def template_mix(mix, listen)
|
def template_mix(mix, listen)
|
||||||
html = <<-END_HTML
|
html = <<-END_HTML
|
||||||
<h3>
|
<h3>
|
||||||
<a href="/mix?list=#{mix["mixId"]}">
|
<a href="/mix?list=#{mix["mixId"]}">
|
||||||
#{mix["title"]}
|
#{mix["title"]}
|
||||||
</a>
|
</a>
|
||||||
</h3>
|
</h3>
|
||||||
<div class="pure-menu pure-menu-scrollable playlist-restricted">
|
<div class="pure-menu pure-menu-scrollable playlist-restricted">
|
||||||
<ol class="pure-menu-list">
|
<ol class="pure-menu-list">
|
||||||
END_HTML
|
END_HTML
|
||||||
|
|
||||||
mix["videos"].as_a.each do |video|
|
mix["videos"].as_a.each do |video|
|
||||||
html += <<-END_HTML
|
html += <<-END_HTML
|
||||||
@ -106,14 +106,14 @@ def template_mix(mix, listen)
|
|||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
END_HTML
|
END_HTML
|
||||||
end
|
end
|
||||||
|
|
||||||
html += <<-END_HTML
|
html += <<-END_HTML
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
END_HTML
|
END_HTML
|
||||||
|
|
||||||
html
|
html
|
||||||
end
|
end
|
||||||
|
|||||||
@ -500,10 +500,10 @@ def extract_playlist_videos(playlist_id : String, initial_data : Hash(String, JS
|
|||||||
|
|
||||||
# Find the metadataParts with commandRuns inside, which contains author
|
# Find the metadataParts with commandRuns inside, which contains author
|
||||||
# information.
|
# information.
|
||||||
metadata_parts = metadata_rows.try &.find { |row|
|
metadata_parts = metadata_rows.try &.find do |row|
|
||||||
parts = row["metadataParts"]?.try &.as_a
|
parts = row["metadataParts"]?.try &.as_a
|
||||||
parts && parts.any? { |item2| item2.dig?("text", "commandRuns").try &.as_a }
|
parts && parts.any? { |item2| item2.dig?("text", "commandRuns").try &.as_a }
|
||||||
}.try &.["metadataParts"].as_a
|
end.try &.["metadataParts"].as_a
|
||||||
|
|
||||||
if author_info = metadata_parts.try &.find(&.dig?("text", "commandRuns"))
|
if author_info = metadata_parts.try &.find(&.dig?("text", "commandRuns"))
|
||||||
.try &.["text"]
|
.try &.["text"]
|
||||||
@ -543,14 +543,14 @@ end
|
|||||||
|
|
||||||
def template_playlist(playlist, listen)
|
def template_playlist(playlist, listen)
|
||||||
html = <<-END_HTML
|
html = <<-END_HTML
|
||||||
<h3>
|
<h3>
|
||||||
<a href="/playlist?list=#{playlist["playlistId"]}">
|
<a href="/playlist?list=#{playlist["playlistId"]}">
|
||||||
#{playlist["title"]}
|
#{playlist["title"]}
|
||||||
</a>
|
</a>
|
||||||
</h3>
|
</h3>
|
||||||
<div class="pure-menu pure-menu-scrollable playlist-restricted">
|
<div class="pure-menu pure-menu-scrollable playlist-restricted">
|
||||||
<ol class="pure-menu-list">
|
<ol class="pure-menu-list">
|
||||||
END_HTML
|
END_HTML
|
||||||
|
|
||||||
playlist["videos"].as_a.each do |video|
|
playlist["videos"].as_a.each do |video|
|
||||||
html += <<-END_HTML
|
html += <<-END_HTML
|
||||||
@ -566,14 +566,14 @@ def template_playlist(playlist, listen)
|
|||||||
</p>
|
</p>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
END_HTML
|
END_HTML
|
||||||
end
|
end
|
||||||
|
|
||||||
html += <<-END_HTML
|
html += <<-END_HTML
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
END_HTML
|
END_HTML
|
||||||
|
|
||||||
html
|
html
|
||||||
end
|
end
|
||||||
|
|||||||
@ -19,9 +19,9 @@ module Invidious::Routes::API::Manifest
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
video = get_video(id, region: region)
|
video = get_video(id, region: region)
|
||||||
rescue ex : NotFoundException
|
rescue NotFoundException
|
||||||
haltf env, status_code: 404
|
haltf env, status_code: 404
|
||||||
rescue ex
|
rescue
|
||||||
haltf env, status_code: 403
|
haltf env, status_code: 403
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -42,11 +42,11 @@ module Invidious::Routes::API::V1::Authenticated
|
|||||||
user = env.get("user").as(User)
|
user = env.get("user").as(User)
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if body = env.request.body
|
body = if raw_body = env.request.body
|
||||||
body = env.request.body.not_nil!.gets_to_end
|
raw_body.gets_to_end
|
||||||
else
|
else
|
||||||
body = "{}"
|
"{}"
|
||||||
end
|
end
|
||||||
Invidious::User::Import.from_invidious(user, body)
|
Invidious::User::Import.from_invidious(user, body)
|
||||||
rescue
|
rescue
|
||||||
end
|
end
|
||||||
|
|||||||
@ -31,7 +31,7 @@ module Invidious::Routes::API::V1::Channels
|
|||||||
begin
|
begin
|
||||||
playlist = get_playlist(channel.ucid.sub("UC", "UULF"))
|
playlist = get_playlist(channel.ucid.sub("UC", "UULF"))
|
||||||
videos = get_playlist_videos(playlist, offset: 0)
|
videos = get_playlist_videos(playlist, offset: 0)
|
||||||
rescue ex : InfoException
|
rescue InfoException
|
||||||
# playlist doesnt exist.
|
# playlist doesnt exist.
|
||||||
videos = [] of PlaylistVideo
|
videos = [] of PlaylistVideo
|
||||||
end
|
end
|
||||||
@ -118,7 +118,7 @@ module Invidious::Routes::API::V1::Channels
|
|||||||
# Fetch related channels
|
# Fetch related channels
|
||||||
begin
|
begin
|
||||||
related_channels, _ = fetch_related_channels(channel)
|
related_channels, _ = fetch_related_channels(channel)
|
||||||
rescue ex
|
rescue
|
||||||
related_channels = [] of SearchChannel
|
related_channels = [] of SearchChannel
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ module Invidious::Routes::API::V1::Channels
|
|||||||
begin
|
begin
|
||||||
playlist = get_playlist(channel.ucid.sub("UC", "UULF"))
|
playlist = get_playlist(channel.ucid.sub("UC", "UULF"))
|
||||||
videos = get_playlist_videos(playlist, offset: 0)
|
videos = get_playlist_videos(playlist, offset: 0)
|
||||||
rescue ex : InfoException
|
rescue InfoException
|
||||||
# playlist doesnt exist.
|
# playlist doesnt exist.
|
||||||
videos = [] of PlaylistVideo
|
videos = [] of PlaylistVideo
|
||||||
end
|
end
|
||||||
@ -203,7 +203,7 @@ module Invidious::Routes::API::V1::Channels
|
|||||||
begin
|
begin
|
||||||
playlist = get_playlist(channel.ucid.sub("UC", "UUSH"))
|
playlist = get_playlist(channel.ucid.sub("UC", "UUSH"))
|
||||||
videos = get_playlist_videos(playlist, offset: 0)
|
videos = get_playlist_videos(playlist, offset: 0)
|
||||||
rescue ex : InfoException
|
rescue InfoException
|
||||||
# playlist doesnt exist.
|
# playlist doesnt exist.
|
||||||
videos = [] of PlaylistVideo
|
videos = [] of PlaylistVideo
|
||||||
end
|
end
|
||||||
@ -249,7 +249,7 @@ module Invidious::Routes::API::V1::Channels
|
|||||||
begin
|
begin
|
||||||
playlist = get_playlist(channel.ucid.sub("UC", "UULV"))
|
playlist = get_playlist(channel.ucid.sub("UC", "UULV"))
|
||||||
videos = get_playlist_videos(playlist, offset: 0)
|
videos = get_playlist_videos(playlist, offset: 0)
|
||||||
rescue ex : InfoException
|
rescue InfoException
|
||||||
# playlist doesnt exist.
|
# playlist doesnt exist.
|
||||||
videos = [] of PlaylistVideo
|
videos = [] of PlaylistVideo
|
||||||
end
|
end
|
||||||
|
|||||||
@ -53,7 +53,7 @@ module Invidious::Routes::API::V1::Misc
|
|||||||
playlist = get_playlist(plid)
|
playlist = get_playlist(plid)
|
||||||
rescue ex : InfoException
|
rescue ex : InfoException
|
||||||
return error_json(404, ex)
|
return error_json(404, ex)
|
||||||
rescue ex
|
rescue
|
||||||
return error_json(404, "Playlist does not exist.")
|
return error_json(404, "Playlist does not exist.")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -47,9 +47,9 @@ module Invidious::Routes::API::V1::Videos
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
video = get_video(id, region: region)
|
video = get_video(id, region: region)
|
||||||
rescue ex : NotFoundException
|
rescue NotFoundException
|
||||||
haltf env, 404
|
haltf env, 404
|
||||||
rescue ex
|
rescue
|
||||||
haltf env, 500
|
haltf env, 500
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -187,9 +187,9 @@ module Invidious::Routes::API::V1::Videos
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
video = get_video(id, region: region)
|
video = get_video(id, region: region)
|
||||||
rescue ex : NotFoundException
|
rescue NotFoundException
|
||||||
haltf env, 404
|
haltf env, 404
|
||||||
rescue ex
|
rescue
|
||||||
haltf env, 500
|
haltf env, 500
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -265,8 +265,6 @@ module Invidious::Routes::API::V1::Videos
|
|||||||
haltf env, 400
|
haltf env, 400
|
||||||
end
|
end
|
||||||
|
|
||||||
annotations = ""
|
|
||||||
|
|
||||||
case source
|
case source
|
||||||
when "archive"
|
when "archive"
|
||||||
if CONFIG.cache_annotations && (cached_annotation = Invidious::Database::Annotations.select(video_id))
|
if CONFIG.cache_annotations && (cached_annotation = Invidious::Database::Annotations.select(video_id))
|
||||||
@ -365,7 +363,7 @@ module Invidious::Routes::API::V1::Videos
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
comments, reddit_thread = Comments.fetch_reddit(id, sort_by: sort_by)
|
comments, reddit_thread = Comments.fetch_reddit(id, sort_by: sort_by)
|
||||||
rescue ex
|
rescue
|
||||||
comments = nil
|
comments = nil
|
||||||
reddit_thread = nil
|
reddit_thread = nil
|
||||||
end
|
end
|
||||||
|
|||||||
@ -44,7 +44,7 @@ module Invidious::Routes::Channels
|
|||||||
begin
|
begin
|
||||||
playlist = get_playlist(channel.ucid.sub("UC", "UULF"))
|
playlist = get_playlist(channel.ucid.sub("UC", "UULF"))
|
||||||
items = get_playlist_videos(playlist, offset: 0)
|
items = get_playlist_videos(playlist, offset: 0)
|
||||||
rescue ex : InfoException
|
rescue InfoException
|
||||||
# playlist doesnt exist.
|
# playlist doesnt exist.
|
||||||
items = [] of PlaylistVideo
|
items = [] of PlaylistVideo
|
||||||
end
|
end
|
||||||
@ -79,7 +79,7 @@ module Invidious::Routes::Channels
|
|||||||
begin
|
begin
|
||||||
playlist = get_playlist(channel.ucid.sub("UC", "UUSH"))
|
playlist = get_playlist(channel.ucid.sub("UC", "UUSH"))
|
||||||
items = get_playlist_videos(playlist, offset: 0)
|
items = get_playlist_videos(playlist, offset: 0)
|
||||||
rescue ex : InfoException
|
rescue InfoException
|
||||||
# playlist doesnt exist.
|
# playlist doesnt exist.
|
||||||
items = [] of PlaylistVideo
|
items = [] of PlaylistVideo
|
||||||
end
|
end
|
||||||
@ -114,7 +114,7 @@ module Invidious::Routes::Channels
|
|||||||
begin
|
begin
|
||||||
playlist = get_playlist(channel.ucid.sub("UC", "UULV"))
|
playlist = get_playlist(channel.ucid.sub("UC", "UULV"))
|
||||||
items = get_playlist_videos(playlist, offset: 0)
|
items = get_playlist_videos(playlist, offset: 0)
|
||||||
rescue ex : InfoException
|
rescue InfoException
|
||||||
# playlist doesnt exist.
|
# playlist doesnt exist.
|
||||||
items = [] of PlaylistVideo
|
items = [] of PlaylistVideo
|
||||||
end
|
end
|
||||||
@ -353,7 +353,7 @@ module Invidious::Routes::Channels
|
|||||||
begin
|
begin
|
||||||
resolved_url = YoutubeAPI.resolve_url("https://www.youtube.com#{env.request.path}#{yt_url_params.size > 0 ? "?#{yt_url_params}" : ""}")
|
resolved_url = YoutubeAPI.resolve_url("https://www.youtube.com#{env.request.path}#{yt_url_params.size > 0 ? "?#{yt_url_params}" : ""}")
|
||||||
ucid = resolved_url["endpoint"]["browseEndpoint"]["browseId"]
|
ucid = resolved_url["endpoint"]["browseEndpoint"]["browseId"]
|
||||||
rescue ex : InfoException | KeyError
|
rescue InfoException | KeyError
|
||||||
return error_template(404, I18n.translate(locale, "This channel does not exist."))
|
return error_template(404, I18n.translate(locale, "This channel does not exist."))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ module Invidious::Routes::Companion
|
|||||||
return self.proxy_companion(env, resp)
|
return self.proxy_companion(env, resp)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ module Invidious::Routes::Companion
|
|||||||
return self.proxy_companion(env, resp)
|
return self.proxy_companion(env, resp)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ module Invidious::Routes::Companion
|
|||||||
return self.proxy_companion(env, resp)
|
return self.proxy_companion(env, resp)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -119,7 +119,6 @@ module Invidious::Routes::Embed
|
|||||||
end
|
end
|
||||||
|
|
||||||
return env.redirect url
|
return env.redirect url
|
||||||
else nil # Continue
|
|
||||||
end
|
end
|
||||||
|
|
||||||
params = Invidious::Videos.process_video_params(env.params.query, preferences)
|
params = Invidious::Videos.process_video_params(env.params.query, preferences)
|
||||||
@ -182,14 +181,14 @@ module Invidious::Routes::Embed
|
|||||||
|
|
||||||
captions = video.captions
|
captions = video.captions
|
||||||
|
|
||||||
preferred_captions = captions.select { |caption|
|
preferred_captions = captions.select do |caption|
|
||||||
params.preferred_captions.includes?(caption.name) ||
|
params.preferred_captions.includes?(caption.name) ||
|
||||||
params.preferred_captions.includes?(caption.language_code.split("-")[0])
|
params.preferred_captions.includes?(caption.language_code.split("-")[0])
|
||||||
}
|
end
|
||||||
preferred_captions.sort_by! { |caption|
|
preferred_captions.sort_by! do |caption|
|
||||||
(params.preferred_captions.index(caption.name) ||
|
(params.preferred_captions.index(caption.name) ||
|
||||||
params.preferred_captions.index(caption.language_code.split("-")[0])).not_nil!
|
params.preferred_captions.index(caption.language_code.split("-")[0])).not_nil!
|
||||||
}
|
end
|
||||||
captions = captions - preferred_captions
|
captions = captions - preferred_captions
|
||||||
|
|
||||||
aspect_ratio = nil
|
aspect_ratio = nil
|
||||||
|
|||||||
@ -327,7 +327,6 @@ module Invidious::Routes::Feeds
|
|||||||
request_target = URI.parse(node[attribute.name]).request_target
|
request_target = URI.parse(node[attribute.name]).request_target
|
||||||
query_string_opt = request_target.starts_with?("/watch?v=") ? ("&#{params}" if !params.empty?) : ""
|
query_string_opt = request_target.starts_with?("/watch?v=") ? ("&#{params}" if !params.empty?) : ""
|
||||||
node[attribute.name] = "#{HOST_URL}#{request_target}#{query_string_opt}"
|
node[attribute.name] = "#{HOST_URL}#{request_target}#{query_string_opt}"
|
||||||
else nil # Skip
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -15,7 +15,7 @@ module Invidious::Routes::Images
|
|||||||
GGPHT_POOL.client &.get(url, headers) do |resp|
|
GGPHT_POOL.client &.get(url, headers) do |resp|
|
||||||
return self.proxy_image(env, resp)
|
return self.proxy_image(env, resp)
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ module Invidious::Routes::Images
|
|||||||
env.response.headers["Connection"] = "close"
|
env.response.headers["Connection"] = "close"
|
||||||
return self.proxy_image(env, resp)
|
return self.proxy_image(env, resp)
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ module Invidious::Routes::Images
|
|||||||
get_ytimg_pool(authority).client &.get(url, headers) do |resp|
|
get_ytimg_pool(authority).client &.get(url, headers) do |resp|
|
||||||
return self.proxy_image(env, resp)
|
return self.proxy_image(env, resp)
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ module Invidious::Routes::Images
|
|||||||
|
|
||||||
Helpers.proxy_file(response, env)
|
Helpers.proxy_file(response, env)
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ module Invidious::Routes::Images
|
|||||||
get_ytimg_pool("i").client &.get(url, headers) do |resp|
|
get_ytimg_pool("i").client &.get(url, headers) do |resp|
|
||||||
return self.proxy_image(env, resp)
|
return self.proxy_image(env, resp)
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -103,7 +103,7 @@ module Invidious::Routes::Login
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
validate_request(tokens[0], answer, env.request, HMAC_KEY, locale)
|
validate_request(tokens[0], answer, env.request, HMAC_KEY, locale)
|
||||||
rescue ex : InfoException
|
rescue InfoException
|
||||||
return error_template(400, InfoException.new("Erroneous CAPTCHA"))
|
return error_template(400, InfoException.new("Erroneous CAPTCHA"))
|
||||||
rescue ex
|
rescue ex
|
||||||
return error_template(400, ex)
|
return error_template(400, ex)
|
||||||
|
|||||||
@ -164,7 +164,7 @@ module Invidious::Routes::Playlists
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
items = get_playlist_videos(playlist, offset: (page - 1) * 100)
|
items = get_playlist_videos(playlist, offset: (page - 1) * 100)
|
||||||
rescue ex
|
rescue
|
||||||
items = [] of PlaylistVideo
|
items = [] of PlaylistVideo
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -255,7 +255,7 @@ module Invidious::Routes::Playlists
|
|||||||
begin
|
begin
|
||||||
query = Invidious::Search::Query.new(env.params.query, :playlist, region)
|
query = Invidious::Search::Query.new(env.params.query, :playlist, region)
|
||||||
items = query.process.select(SearchVideo).map(&.as(SearchVideo))
|
items = query.process.select(SearchVideo).map(&.as(SearchVideo))
|
||||||
rescue ex
|
rescue
|
||||||
items = [] of SearchVideo
|
items = [] of SearchVideo
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -362,7 +362,6 @@ module Invidious::Routes::PreferencesRoute
|
|||||||
response: error_template(415, "Uploaded file is too large")
|
response: error_template(415, "Uploaded file is too large")
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
else nil # Ignore
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -115,7 +115,7 @@ module Invidious::Routes::VideoPlayback
|
|||||||
|
|
||||||
IO.copy(resp.body_io, env.response)
|
IO.copy(resp.body_io, env.response)
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if query_params["title"]? && CONFIG.disabled?("downloads") ||
|
if query_params["title"]? && CONFIG.disabled?("downloads") ||
|
||||||
|
|||||||
@ -82,7 +82,7 @@ module Invidious::Routes::Watch
|
|||||||
if source == "youtube"
|
if source == "youtube"
|
||||||
begin
|
begin
|
||||||
comment_html = JSON.parse(Comments.fetch_youtube(id, nil, "html", locale, preferences.thin_mode, region))["contentHtml"]
|
comment_html = JSON.parse(Comments.fetch_youtube(id, nil, "html", locale, preferences.thin_mode, region))["contentHtml"]
|
||||||
rescue ex
|
rescue
|
||||||
if preferences.comments[1] == "reddit"
|
if preferences.comments[1] == "reddit"
|
||||||
comments, reddit_thread = Comments.fetch_reddit(id)
|
comments, reddit_thread = Comments.fetch_reddit(id)
|
||||||
comment_html = Frontend::Comments.template_reddit(comments, locale)
|
comment_html = Frontend::Comments.template_reddit(comments, locale)
|
||||||
@ -98,7 +98,7 @@ module Invidious::Routes::Watch
|
|||||||
|
|
||||||
comment_html = Comments.fill_links(comment_html, "https", "www.reddit.com")
|
comment_html = Comments.fill_links(comment_html, "https", "www.reddit.com")
|
||||||
comment_html = Comments.replace_links(comment_html)
|
comment_html = Comments.replace_links(comment_html)
|
||||||
rescue ex
|
rescue
|
||||||
if preferences.comments[1] == "youtube"
|
if preferences.comments[1] == "youtube"
|
||||||
comment_html = JSON.parse(Comments.fetch_youtube(id, nil, "html", locale, preferences.thin_mode, region))["contentHtml"]
|
comment_html = JSON.parse(Comments.fetch_youtube(id, nil, "html", locale, preferences.thin_mode, region))["contentHtml"]
|
||||||
end
|
end
|
||||||
@ -143,14 +143,14 @@ module Invidious::Routes::Watch
|
|||||||
|
|
||||||
captions = video.captions
|
captions = video.captions
|
||||||
|
|
||||||
preferred_captions = captions.select { |caption|
|
preferred_captions = captions.select do |caption|
|
||||||
params.preferred_captions.includes?(caption.name) ||
|
params.preferred_captions.includes?(caption.name) ||
|
||||||
params.preferred_captions.includes?(caption.language_code.split("-")[0])
|
params.preferred_captions.includes?(caption.language_code.split("-")[0])
|
||||||
}
|
end
|
||||||
preferred_captions.sort_by! { |caption|
|
preferred_captions.sort_by! do |caption|
|
||||||
(params.preferred_captions.index(caption.name) ||
|
(params.preferred_captions.index(caption.name) ||
|
||||||
params.preferred_captions.index(caption.language_code.split("-")[0])).not_nil!
|
params.preferred_captions.index(caption.language_code.split("-")[0])).not_nil!
|
||||||
}
|
end
|
||||||
captions = captions - preferred_captions
|
captions = captions - preferred_captions
|
||||||
|
|
||||||
aspect_ratio = "16:9"
|
aspect_ratio = "16:9"
|
||||||
|
|||||||
@ -3,12 +3,12 @@ module Invidious::Routing
|
|||||||
|
|
||||||
{% for http_method in {"get", "post", "delete", "options", "patch", "put"} %}
|
{% for http_method in {"get", "post", "delete", "options", "patch", "put"} %}
|
||||||
|
|
||||||
macro {{http_method.id}}(path, controller, method = :handle)
|
macro {{ http_method.id }}(path, controller, method = :handle)
|
||||||
unless Kemal::Utils.path_starts_with_slash?(\{{path}})
|
unless Kemal::Utils.path_starts_with_slash?(\{{path}})
|
||||||
raise Kemal::Exceptions::InvalidPathStartException.new({{http_method}}, \{{path}})
|
raise Kemal::Exceptions::InvalidPathStartException.new({{ http_method }}, \{{path}})
|
||||||
end
|
end
|
||||||
|
|
||||||
Kemal::RouteHandler::INSTANCE.add_route({{http_method.upcase}}, \{{path}}) do |env|
|
Kemal::RouteHandler::INSTANCE.add_route({{ http_method.upcase }}, \{{path}}) do |env|
|
||||||
\{{ controller }}.\{{ method.id }}(env)
|
\{{ controller }}.\{{ method.id }}(env)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -241,91 +241,91 @@ module Invidious::Routing
|
|||||||
|
|
||||||
def register_api_v1_routes
|
def register_api_v1_routes
|
||||||
{% begin %}
|
{% begin %}
|
||||||
{{namespace = Routes::API::V1}}
|
{{ namespace = Routes::API::V1 }}
|
||||||
|
|
||||||
# Videos
|
# Videos
|
||||||
get "/api/v1/videos/:id", {{namespace}}::Videos, :videos
|
get "/api/v1/videos/:id", {{ namespace }}::Videos, :videos
|
||||||
get "/api/v1/storyboards/:id", {{namespace}}::Videos, :storyboards
|
get "/api/v1/storyboards/:id", {{ namespace }}::Videos, :storyboards
|
||||||
get "/api/v1/captions/:id", {{namespace}}::Videos, :captions
|
get "/api/v1/captions/:id", {{ namespace }}::Videos, :captions
|
||||||
get "/api/v1/annotations/:id", {{namespace}}::Videos, :annotations
|
get "/api/v1/annotations/:id", {{ namespace }}::Videos, :annotations
|
||||||
get "/api/v1/comments/:id", {{namespace}}::Videos, :comments
|
get "/api/v1/comments/:id", {{ namespace }}::Videos, :comments
|
||||||
get "/api/v1/clips/:id", {{namespace}}::Videos, :clips
|
get "/api/v1/clips/:id", {{ namespace }}::Videos, :clips
|
||||||
get "/api/v1/transcripts/:id", {{namespace}}::Videos, :transcripts
|
get "/api/v1/transcripts/:id", {{ namespace }}::Videos, :transcripts
|
||||||
|
|
||||||
# Feeds
|
# Feeds
|
||||||
get "/api/v1/trending", {{namespace}}::Feeds, :trending
|
get "/api/v1/trending", {{ namespace }}::Feeds, :trending
|
||||||
get "/api/v1/popular", {{namespace}}::Feeds, :popular
|
get "/api/v1/popular", {{ namespace }}::Feeds, :popular
|
||||||
|
|
||||||
# Channels
|
# Channels
|
||||||
get "/api/v1/channels/:ucid", {{namespace}}::Channels, :home
|
get "/api/v1/channels/:ucid", {{ namespace }}::Channels, :home
|
||||||
get "/api/v1/channels/:ucid/latest", {{namespace}}::Channels, :latest
|
get "/api/v1/channels/:ucid/latest", {{ namespace }}::Channels, :latest
|
||||||
get "/api/v1/channels/:ucid/videos", {{namespace}}::Channels, :videos
|
get "/api/v1/channels/:ucid/videos", {{ namespace }}::Channels, :videos
|
||||||
get "/api/v1/channels/:ucid/shorts", {{namespace}}::Channels, :shorts
|
get "/api/v1/channels/:ucid/shorts", {{ namespace }}::Channels, :shorts
|
||||||
get "/api/v1/channels/:ucid/streams", {{namespace}}::Channels, :streams
|
get "/api/v1/channels/:ucid/streams", {{ namespace }}::Channels, :streams
|
||||||
get "/api/v1/channels/:ucid/podcasts", {{namespace}}::Channels, :podcasts
|
get "/api/v1/channels/:ucid/podcasts", {{ namespace }}::Channels, :podcasts
|
||||||
get "/api/v1/channels/:ucid/releases", {{namespace}}::Channels, :releases
|
get "/api/v1/channels/:ucid/releases", {{ namespace }}::Channels, :releases
|
||||||
get "/api/v1/channels/:ucid/courses", {{namespace}}::Channels, :courses
|
get "/api/v1/channels/:ucid/courses", {{ namespace }}::Channels, :courses
|
||||||
get "/api/v1/channels/:ucid/playlists", {{namespace}}::Channels, :playlists
|
get "/api/v1/channels/:ucid/playlists", {{ namespace }}::Channels, :playlists
|
||||||
get "/api/v1/channels/:ucid/community", {{namespace}}::Channels, :community
|
get "/api/v1/channels/:ucid/community", {{ namespace }}::Channels, :community
|
||||||
get "/api/v1/channels/:ucid/posts", {{namespace}}::Channels, :community
|
get "/api/v1/channels/:ucid/posts", {{ namespace }}::Channels, :community
|
||||||
get "/api/v1/channels/:ucid/channels", {{namespace}}::Channels, :channels
|
get "/api/v1/channels/:ucid/channels", {{ namespace }}::Channels, :channels
|
||||||
get "/api/v1/channels/:ucid/search", {{namespace}}::Channels, :search
|
get "/api/v1/channels/:ucid/search", {{ namespace }}::Channels, :search
|
||||||
|
|
||||||
# Posts
|
# Posts
|
||||||
get "/api/v1/post/:id", {{namespace}}::Channels, :post
|
get "/api/v1/post/:id", {{ namespace }}::Channels, :post
|
||||||
get "/api/v1/post/:id/comments", {{namespace}}::Channels, :post_comments
|
get "/api/v1/post/:id/comments", {{ namespace }}::Channels, :post_comments
|
||||||
|
|
||||||
# 301 redirects to new /api/v1/channels/community/:ucid and /:ucid/community
|
# 301 redirects to new /api/v1/channels/community/:ucid and /:ucid/community
|
||||||
get "/api/v1/channels/comments/:ucid", {{namespace}}::Channels, :channel_comments_redirect
|
get "/api/v1/channels/comments/:ucid", {{ namespace }}::Channels, :channel_comments_redirect
|
||||||
get "/api/v1/channels/:ucid/comments", {{namespace}}::Channels, :channel_comments_redirect
|
get "/api/v1/channels/:ucid/comments", {{ namespace }}::Channels, :channel_comments_redirect
|
||||||
|
|
||||||
# Search
|
# Search
|
||||||
get "/api/v1/search", {{namespace}}::Search, :search
|
get "/api/v1/search", {{ namespace }}::Search, :search
|
||||||
get "/api/v1/search/suggestions", {{namespace}}::Search, :search_suggestions
|
get "/api/v1/search/suggestions", {{ namespace }}::Search, :search_suggestions
|
||||||
get "/api/v1/hashtag/:hashtag", {{namespace}}::Search, :hashtag
|
get "/api/v1/hashtag/:hashtag", {{ namespace }}::Search, :hashtag
|
||||||
|
|
||||||
|
|
||||||
# Authenticated
|
# Authenticated
|
||||||
|
|
||||||
get "/api/v1/auth/preferences", {{namespace}}::Authenticated, :get_preferences
|
get "/api/v1/auth/preferences", {{ namespace }}::Authenticated, :get_preferences
|
||||||
post "/api/v1/auth/preferences", {{namespace}}::Authenticated, :set_preferences
|
post "/api/v1/auth/preferences", {{ namespace }}::Authenticated, :set_preferences
|
||||||
|
|
||||||
get "/api/v1/auth/export/invidious", {{namespace}}::Authenticated, :export_invidious
|
get "/api/v1/auth/export/invidious", {{ namespace }}::Authenticated, :export_invidious
|
||||||
post "/api/v1/auth/import/invidious", {{namespace}}::Authenticated, :import_invidious
|
post "/api/v1/auth/import/invidious", {{ namespace }}::Authenticated, :import_invidious
|
||||||
|
|
||||||
get "/api/v1/auth/history", {{namespace}}::Authenticated, :get_history
|
get "/api/v1/auth/history", {{ namespace }}::Authenticated, :get_history
|
||||||
post "/api/v1/auth/history/:id", {{namespace}}::Authenticated, :mark_watched
|
post "/api/v1/auth/history/:id", {{ namespace }}::Authenticated, :mark_watched
|
||||||
delete "/api/v1/auth/history/:id", {{namespace}}::Authenticated, :mark_unwatched
|
delete "/api/v1/auth/history/:id", {{ namespace }}::Authenticated, :mark_unwatched
|
||||||
delete "/api/v1/auth/history", {{namespace}}::Authenticated, :clear_history
|
delete "/api/v1/auth/history", {{ namespace }}::Authenticated, :clear_history
|
||||||
|
|
||||||
get "/api/v1/auth/feed", {{namespace}}::Authenticated, :feed
|
get "/api/v1/auth/feed", {{ namespace }}::Authenticated, :feed
|
||||||
|
|
||||||
get "/api/v1/auth/subscriptions", {{namespace}}::Authenticated, :get_subscriptions
|
get "/api/v1/auth/subscriptions", {{ namespace }}::Authenticated, :get_subscriptions
|
||||||
post "/api/v1/auth/subscriptions/:ucid", {{namespace}}::Authenticated, :subscribe_channel
|
post "/api/v1/auth/subscriptions/:ucid", {{ namespace }}::Authenticated, :subscribe_channel
|
||||||
delete "/api/v1/auth/subscriptions/:ucid", {{namespace}}::Authenticated, :unsubscribe_channel
|
delete "/api/v1/auth/subscriptions/:ucid", {{ namespace }}::Authenticated, :unsubscribe_channel
|
||||||
|
|
||||||
get "/api/v1/auth/playlists", {{namespace}}::Authenticated, :list_playlists
|
get "/api/v1/auth/playlists", {{ namespace }}::Authenticated, :list_playlists
|
||||||
post "/api/v1/auth/playlists", {{namespace}}::Authenticated, :create_playlist
|
post "/api/v1/auth/playlists", {{ namespace }}::Authenticated, :create_playlist
|
||||||
patch "/api/v1/auth/playlists/:plid",{{namespace}}:: Authenticated, :update_playlist_attribute
|
patch "/api/v1/auth/playlists/:plid",{{ namespace }}:: Authenticated, :update_playlist_attribute
|
||||||
delete "/api/v1/auth/playlists/:plid", {{namespace}}::Authenticated, :delete_playlist
|
delete "/api/v1/auth/playlists/:plid", {{ namespace }}::Authenticated, :delete_playlist
|
||||||
post "/api/v1/auth/playlists/:plid/videos", {{namespace}}::Authenticated, :insert_video_into_playlist
|
post "/api/v1/auth/playlists/:plid/videos", {{ namespace }}::Authenticated, :insert_video_into_playlist
|
||||||
delete "/api/v1/auth/playlists/:plid/videos/:index", {{namespace}}::Authenticated, :delete_video_in_playlist
|
delete "/api/v1/auth/playlists/:plid/videos/:index", {{ namespace }}::Authenticated, :delete_video_in_playlist
|
||||||
|
|
||||||
get "/api/v1/auth/tokens", {{namespace}}::Authenticated, :get_tokens
|
get "/api/v1/auth/tokens", {{ namespace }}::Authenticated, :get_tokens
|
||||||
post "/api/v1/auth/tokens/register", {{namespace}}::Authenticated, :register_token
|
post "/api/v1/auth/tokens/register", {{ namespace }}::Authenticated, :register_token
|
||||||
post "/api/v1/auth/tokens/unregister", {{namespace}}::Authenticated, :unregister_token
|
post "/api/v1/auth/tokens/unregister", {{ namespace }}::Authenticated, :unregister_token
|
||||||
|
|
||||||
if CONFIG.enable_user_notifications
|
if CONFIG.enable_user_notifications
|
||||||
get "/api/v1/auth/notifications", {{namespace}}::Authenticated, :notifications
|
get "/api/v1/auth/notifications", {{ namespace }}::Authenticated, :notifications
|
||||||
post "/api/v1/auth/notifications", {{namespace}}::Authenticated, :notifications
|
post "/api/v1/auth/notifications", {{ namespace }}::Authenticated, :notifications
|
||||||
end
|
end
|
||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
get "/api/v1/stats", {{namespace}}::Misc, :stats
|
get "/api/v1/stats", {{ namespace }}::Misc, :stats
|
||||||
get "/api/v1/playlists/:plid", {{namespace}}::Misc, :get_playlist
|
get "/api/v1/playlists/:plid", {{ namespace }}::Misc, :get_playlist
|
||||||
get "/api/v1/auth/playlists/:plid", {{namespace}}::Misc, :get_playlist
|
get "/api/v1/auth/playlists/:plid", {{ namespace }}::Misc, :get_playlist
|
||||||
get "/api/v1/mixes/:rdid", {{namespace}}::Misc, :mixes
|
get "/api/v1/mixes/:rdid", {{ namespace }}::Misc, :mixes
|
||||||
get "/api/v1/resolveurl", {{namespace}}::Misc, :resolve_url
|
get "/api/v1/resolveurl", {{ namespace }}::Misc, :resolve_url
|
||||||
{% end %}
|
{% end %}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -39,7 +39,7 @@ module Invidious::Search
|
|||||||
def subscriptions(query : Query, user : Invidious::User) : Array(ChannelVideo)
|
def subscriptions(query : Query, user : Invidious::User) : Array(ChannelVideo)
|
||||||
view_name = "subscriptions_#{sha256(user.email)}"
|
view_name = "subscriptions_#{sha256(user.email)}"
|
||||||
|
|
||||||
return PG_DB.query_all("
|
return PG_DB.query_all(<<-SQL,
|
||||||
SELECT id,title,published,updated,ucid,author,length_seconds
|
SELECT id,title,published,updated,ucid,author,length_seconds
|
||||||
FROM (
|
FROM (
|
||||||
SELECT *,
|
SELECT *,
|
||||||
@ -47,7 +47,8 @@ module Invidious::Search
|
|||||||
to_tsvector(#{view_name}.author)
|
to_tsvector(#{view_name}.author)
|
||||||
as document
|
as document
|
||||||
FROM #{view_name}
|
FROM #{view_name}
|
||||||
) v_search WHERE v_search.document @@ plainto_tsquery($1) LIMIT 20 OFFSET $2;",
|
) v_search WHERE v_search.document @@ plainto_tsquery($1) LIMIT 20 OFFSET $2;
|
||||||
|
SQL
|
||||||
query.text, (query.page - 1) * 20,
|
query.text, (query.page - 1) * 20,
|
||||||
as: ChannelVideo
|
as: ChannelVideo
|
||||||
)
|
)
|
||||||
|
|||||||
@ -2,10 +2,10 @@ def fetch_trending(trending_type, region, locale)
|
|||||||
region ||= "US"
|
region ||= "US"
|
||||||
region = region.upcase
|
region = region.upcase
|
||||||
|
|
||||||
|
# 2026-10-12: plid is only used in line 47
|
||||||
|
# so we can remove this later.
|
||||||
plid = nil
|
plid = nil
|
||||||
|
|
||||||
browse_id = ""
|
|
||||||
|
|
||||||
case trending_type.try &.downcase
|
case trending_type.try &.downcase
|
||||||
when "gaming"
|
when "gaming"
|
||||||
browse_id = "UCOpNcN46UbXVtpKMrmU4Abg"
|
browse_id = "UCOpNcN46UbXVtpKMrmU4Abg"
|
||||||
|
|||||||
@ -20,28 +20,28 @@ struct Invidious::User
|
|||||||
end
|
end
|
||||||
|
|
||||||
clock_svg = <<-END_SVG
|
clock_svg = <<-END_SVG
|
||||||
<svg viewBox="0 0 100 100" width="200px" height="200px">
|
<svg viewBox="0 0 100 100" width="200px" height="200px">
|
||||||
<circle cx="50" cy="50" r="45" fill="#eee" stroke="black" stroke-width="2"></circle>
|
<circle cx="50" cy="50" r="45" fill="#eee" stroke="black" stroke-width="2"></circle>
|
||||||
|
|
||||||
<text x="69" y="20.091" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 1</text>
|
<text x="69" y="20.091" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 1</text>
|
||||||
<text x="82.909" y="34" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 2</text>
|
<text x="82.909" y="34" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 2</text>
|
||||||
<text x="88" y="53" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 3</text>
|
<text x="88" y="53" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 3</text>
|
||||||
<text x="82.909" y="72" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 4</text>
|
<text x="82.909" y="72" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 4</text>
|
||||||
<text x="69" y="85.909" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 5</text>
|
<text x="69" y="85.909" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 5</text>
|
||||||
<text x="50" y="91" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 6</text>
|
<text x="50" y="91" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 6</text>
|
||||||
<text x="31" y="85.909" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 7</text>
|
<text x="31" y="85.909" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 7</text>
|
||||||
<text x="17.091" y="72" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 8</text>
|
<text x="17.091" y="72" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 8</text>
|
||||||
<text x="12" y="53" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 9</text>
|
<text x="12" y="53" text-anchor="middle" fill="black" font-family="Arial" font-size="10px"> 9</text>
|
||||||
<text x="17.091" y="34" text-anchor="middle" fill="black" font-family="Arial" font-size="10px">10</text>
|
<text x="17.091" y="34" text-anchor="middle" fill="black" font-family="Arial" font-size="10px">10</text>
|
||||||
<text x="31" y="20.091" text-anchor="middle" fill="black" font-family="Arial" font-size="10px">11</text>
|
<text x="31" y="20.091" text-anchor="middle" fill="black" font-family="Arial" font-size="10px">11</text>
|
||||||
<text x="50" y="15" text-anchor="middle" fill="black" font-family="Arial" font-size="10px">12</text>
|
<text x="50" y="15" text-anchor="middle" fill="black" font-family="Arial" font-size="10px">12</text>
|
||||||
|
|
||||||
<circle cx="50" cy="50" r="3" fill="black"></circle>
|
<circle cx="50" cy="50" r="3" fill="black"></circle>
|
||||||
<line id="second" transform="rotate(#{second_angle}, 50, 50)" x1="50" y1="50" x2="50" y2="12" fill="black" stroke="black" stroke-width="1"></line>
|
<line id="second" transform="rotate(#{second_angle}, 50, 50)" x1="50" y1="50" x2="50" y2="12" fill="black" stroke="black" stroke-width="1"></line>
|
||||||
<line id="minute" transform="rotate(#{minute_angle}, 50, 50)" x1="50" y1="50" x2="50" y2="16" fill="black" stroke="black" stroke-width="2"></line>
|
<line id="minute" transform="rotate(#{minute_angle}, 50, 50)" x1="50" y1="50" x2="50" y2="16" fill="black" stroke="black" stroke-width="2"></line>
|
||||||
<line id="hour" transform="rotate(#{hour_angle}, 50, 50)" x1="50" y1="50" x2="50" y2="24" fill="black" stroke="black" stroke-width="2"></line>
|
<line id="hour" transform="rotate(#{hour_angle}, 50, 50)" x1="50" y1="50" x2="50" y2="24" fill="black" stroke="black" stroke-width="2"></line>
|
||||||
</svg>
|
</svg>
|
||||||
END_SVG
|
END_SVG
|
||||||
|
|
||||||
image = "data:image/png;base64,"
|
image = "data:image/png;base64,"
|
||||||
image += Process.run(%(rsvg-convert -w 400 -h 400 -b none -f png), shell: true,
|
image += Process.run(%(rsvg-convert -w 400 -h 400 -b none -f png), shell: true,
|
||||||
|
|||||||
@ -56,7 +56,7 @@ struct Invidious::User
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
video = get_video(video_id)
|
video = get_video(video_id)
|
||||||
rescue ex
|
rescue
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ struct Invidious::User
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
video = get_video(video_id, false)
|
video = get_video(video_id, false)
|
||||||
rescue ex
|
rescue
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -73,7 +73,7 @@ struct Preferences
|
|||||||
else
|
else
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
if value.read_bool
|
if value.read_bool
|
||||||
"dark"
|
"dark"
|
||||||
else
|
else
|
||||||
@ -199,7 +199,7 @@ struct Preferences
|
|||||||
value.read_array do
|
value.read_array do
|
||||||
result << HTML.escape(value.read_string[0, 100])
|
result << HTML.escape(value.read_string[0, 100])
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
result = [HTML.escape(value.read_string[0, 100]), ""]
|
result = [HTML.escape(value.read_string[0, 100]), ""]
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ struct Preferences
|
|||||||
|
|
||||||
result << HTML.escape(item.value[0, 100])
|
result << HTML.escape(item.value[0, 100])
|
||||||
end
|
end
|
||||||
rescue ex
|
rescue
|
||||||
if node.is_a?(YAML::Nodes::Scalar)
|
if node.is_a?(YAML::Nodes::Scalar)
|
||||||
result = [HTML.escape(node.value[0, 100]), ""]
|
result = [HTML.escape(node.value[0, 100]), ""]
|
||||||
else
|
else
|
||||||
|
|||||||
@ -19,7 +19,7 @@ struct Invidious::User
|
|||||||
def self.from_rs(rs)
|
def self.from_rs(rs)
|
||||||
begin
|
begin
|
||||||
Preferences.from_json(rs.read(String))
|
Preferences.from_json(rs.read(String))
|
||||||
rescue ex
|
rescue
|
||||||
Preferences.from_json("{}")
|
Preferences.from_json("{}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -45,7 +45,6 @@ def get_subscription_feed(user, max_results = 40, page = 1)
|
|||||||
notifications.sort_by!(&.author)
|
notifications.sort_by!(&.author)
|
||||||
when "channel name - reverse"
|
when "channel name - reverse"
|
||||||
notifications.sort_by!(&.author).reverse!
|
notifications.sort_by!(&.author).reverse!
|
||||||
else nil # Ignore
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if user.preferences.latest_only
|
if user.preferences.latest_only
|
||||||
@ -94,7 +93,6 @@ def get_subscription_feed(user, max_results = 40, page = 1)
|
|||||||
videos.sort_by!(&.author)
|
videos.sort_by!(&.author)
|
||||||
when "channel name - reverse"
|
when "channel name - reverse"
|
||||||
videos.sort_by!(&.author).reverse!
|
videos.sort_by!(&.author).reverse!
|
||||||
else nil # Ignore
|
|
||||||
end
|
end
|
||||||
|
|
||||||
notifications = Invidious::Database::Users.select_notifications(user)
|
notifications = Invidious::Database::Users.select_notifications(user)
|
||||||
|
|||||||
@ -48,7 +48,7 @@ struct Video
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_json(json : JSON::Builder | Nil = nil)
|
def to_json(json : JSON::Builder? = nil)
|
||||||
to_json(nil, json)
|
to_json(nil, json)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ struct Video
|
|||||||
|
|
||||||
def dash_manifest_url : String?
|
def dash_manifest_url : String?
|
||||||
raw_dash_url = info.dig?("streamingData", "dashManifestUrl").try &.as_s
|
raw_dash_url = info.dig?("streamingData", "dashManifestUrl").try &.as_s
|
||||||
return nil if raw_dash_url.nil?
|
return if raw_dash_url.nil?
|
||||||
|
|
||||||
# Use manifest v5 parameter to reduce file size
|
# Use manifest v5 parameter to reduce file size
|
||||||
# See https://github.com/iv-org/invidious/issues/4186
|
# See https://github.com/iv-org/invidious/issues/4186
|
||||||
@ -183,14 +183,14 @@ struct Video
|
|||||||
end
|
end
|
||||||
|
|
||||||
def music : Array(VideoMusic)
|
def music : Array(VideoMusic)
|
||||||
info["music"].as_a.map { |music_json|
|
info["music"].as_a.map do |music_json|
|
||||||
VideoMusic.new(
|
VideoMusic.new(
|
||||||
music_json["song"].as_s,
|
music_json["song"].as_s,
|
||||||
music_json["album"].as_s,
|
music_json["album"].as_s,
|
||||||
music_json["artist"].as_s,
|
music_json["artist"].as_s,
|
||||||
music_json["license"].as_s
|
music_json["license"].as_s
|
||||||
)
|
)
|
||||||
}
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns true if comments are enabled on the video
|
# Returns true if comments are enabled on the video
|
||||||
@ -201,37 +201,37 @@ struct Video
|
|||||||
# Macros defining getters/setters for various types of data
|
# Macros defining getters/setters for various types of data
|
||||||
|
|
||||||
private macro getset_string(name)
|
private macro getset_string(name)
|
||||||
# Return {{name.stringify}} from `info`
|
# Return {{ name.stringify }} from `info`
|
||||||
def {{name.id.underscore}} : String
|
def {{ name.id.underscore }} : String
|
||||||
return info[{{name.stringify}}]?.try &.as_s || ""
|
return info[{{ name.stringify }}]?.try &.as_s || ""
|
||||||
end
|
end
|
||||||
|
|
||||||
# Update {{name.stringify}} into `info`
|
# Update {{ name.stringify }} into `info`
|
||||||
def {{name.id.underscore}}=(value : String)
|
def {{ name.id.underscore }}=(value : String)
|
||||||
info[{{name.stringify}}] = JSON::Any.new(value)
|
info[{{ name.stringify }}] = JSON::Any.new(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
{% if flag?(:debug_macros) %} {{debug}} {% end %}
|
{% if flag?(:debug_macros) %} {{ debug }} {% end %}
|
||||||
end
|
end
|
||||||
|
|
||||||
private macro getset_string_array(name)
|
private macro getset_string_array(name)
|
||||||
# Return {{name.stringify}} from `info`
|
# Return {{ name.stringify }} from `info`
|
||||||
def {{name.id.underscore}} : Array(String)
|
def {{ name.id.underscore }} : Array(String)
|
||||||
return info[{{name.stringify}}]?.try &.as_a.map &.as_s || [] of String
|
return info[{{ name.stringify }}]?.try &.as_a.map &.as_s || [] of String
|
||||||
end
|
end
|
||||||
|
|
||||||
# Update {{name.stringify}} into `info`
|
# Update {{ name.stringify }} into `info`
|
||||||
def {{name.id.underscore}}=(value : Array(String))
|
def {{ name.id.underscore }}=(value : Array(String))
|
||||||
info[{{name.stringify}}] = JSON::Any.new(value)
|
info[{{ name.stringify }}] = JSON::Any.new(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
{% if flag?(:debug_macros) %} {{debug}} {% end %}
|
{% if flag?(:debug_macros) %} {{ debug }} {% end %}
|
||||||
end
|
end
|
||||||
|
|
||||||
{% for op, type in {i32: Int32, i64: Int64} %}
|
{% for op, type in {i32: Int32, i64: Int64} %}
|
||||||
private macro getset_{{op}}(name)
|
private macro getset_{{ op }}(name)
|
||||||
def \{{name.id.underscore}} : {{type}}
|
def \{{name.id.underscore}} : {{ type }}
|
||||||
return info[\{{name.stringify}}]?.try &.as_i64.to_{{op}} || 0_{{op}}
|
return info[\{{name.stringify}}]?.try &.as_i64.to_{{ op }} || 0_{{ op }}
|
||||||
end
|
end
|
||||||
|
|
||||||
def \{{name.id.underscore}}=(value : Int)
|
def \{{name.id.underscore}}=(value : Int)
|
||||||
@ -243,32 +243,32 @@ struct Video
|
|||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
private macro getset_bool(name)
|
private macro getset_bool(name)
|
||||||
# Return {{name.stringify}} from `info`
|
# Return {{ name.stringify }} from `info`
|
||||||
def {{name.id.underscore}} : Bool
|
def {{ name.id.underscore }} : Bool
|
||||||
return info[{{name.stringify}}]?.try &.as_bool || false
|
return info[{{ name.stringify }}]?.try &.as_bool || false
|
||||||
end
|
end
|
||||||
|
|
||||||
# Update {{name.stringify}} into `info`
|
# Update {{ name.stringify }} into `info`
|
||||||
def {{name.id.underscore}}=(value : Bool)
|
def {{ name.id.underscore }}=(value : Bool)
|
||||||
info[{{name.stringify}}] = JSON::Any.new(value)
|
info[{{ name.stringify }}] = JSON::Any.new(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
{% if flag?(:debug_macros) %} {{debug}} {% end %}
|
{% if flag?(:debug_macros) %} {{ debug }} {% end %}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Macro to generate ? and = accessor methods for attributes in `info`
|
# Macro to generate ? and = accessor methods for attributes in `info`
|
||||||
private macro predicate_bool(method_name, name)
|
private macro predicate_bool(method_name, name)
|
||||||
# Return {{name.stringify}} from `info`
|
# Return {{ name.stringify }} from `info`
|
||||||
def {{method_name.id.underscore}}? : Bool
|
def {{ method_name.id.underscore }}? : Bool
|
||||||
return info[{{name.stringify}}]?.try &.as_bool || false
|
return info[{{ name.stringify }}]?.try &.as_bool || false
|
||||||
end
|
end
|
||||||
|
|
||||||
# Update {{name.stringify}} into `info`
|
# Update {{ name.stringify }} into `info`
|
||||||
def {{method_name.id.underscore}}=(value : Bool)
|
def {{ method_name.id.underscore }}=(value : Bool)
|
||||||
info[{{name.stringify}}] = JSON::Any.new(value)
|
info[{{ name.stringify }}] = JSON::Any.new(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
{% if flag?(:debug_macros) %} {{debug}} {% end %}
|
{% if flag?(:debug_macros) %} {{ debug }} {% end %}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Method definitions, using the macros above
|
# Method definitions, using the macros above
|
||||||
|
|||||||
@ -10,7 +10,7 @@ module Invidious::Videos::Parser
|
|||||||
# TODO: "compactRadioRenderer" (Mix) and
|
# TODO: "compactRadioRenderer" (Mix) and
|
||||||
# TODO: Use a proper struct/class instead of a hacky JSON object
|
# TODO: Use a proper struct/class instead of a hacky JSON object
|
||||||
def parse_related_video(related : JSON::Any) : Hash(String, JSON::Any)?
|
def parse_related_video(related : JSON::Any) : Hash(String, JSON::Any)?
|
||||||
return nil if !related["videoId"]?
|
return if !related["videoId"]?
|
||||||
|
|
||||||
# The compact renderer has video length in seconds, where the end
|
# The compact renderer has video length in seconds, where the end
|
||||||
# screen rendered has a full text version ("42:40")
|
# screen rendered has a full text version ("42:40")
|
||||||
@ -60,7 +60,7 @@ module Invidious::Videos::Parser
|
|||||||
player_response = YoutubeAPI.player(video_id: video_id)
|
player_response = YoutubeAPI.player(video_id: video_id)
|
||||||
|
|
||||||
if player_response.nil?
|
if player_response.nil?
|
||||||
return nil
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
playability_status = player_response.dig?("playabilityStatus", "status").try &.as_s
|
playability_status = player_response.dig?("playabilityStatus", "status").try &.as_s
|
||||||
@ -150,7 +150,7 @@ module Invidious::Videos::Parser
|
|||||||
elsif playability_status == "OK"
|
elsif playability_status == "OK"
|
||||||
return response
|
return response
|
||||||
else
|
else
|
||||||
return nil
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -25,8 +25,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% if captcha %>
|
<% if captcha %>
|
||||||
<% captcha = captcha.not_nil! %>
|
<img src='<%= captcha[:question] %>' style="width:50%"/>
|
||||||
<img style="width:50%" src='<%= captcha[:question] %>'/>
|
|
||||||
<% captcha[:tokens].each_with_index do |token, i| %>
|
<% captcha[:tokens].each_with_index do |token, i| %>
|
||||||
<input type="hidden" name="token[<%= i %>]" value="<%= HTML.escape(token) %>">
|
<input type="hidden" name="token[<%= i %>]" value="<%= HTML.escape(token) %>">
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@ -20,7 +20,7 @@ struct YoutubeConnectionPool
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
response = yield conn
|
response = yield conn
|
||||||
rescue ex
|
rescue
|
||||||
conn.close
|
conn.close
|
||||||
conn = make_client(url, force_resolve: true)
|
conn = make_client(url, force_resolve: true)
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ struct CompanionConnectionPool
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
response = yield wrapper
|
response = yield wrapper
|
||||||
rescue ex
|
rescue
|
||||||
wrapper.close
|
wrapper.close
|
||||||
|
|
||||||
companion = CONFIG.invidious_companion.sample
|
companion = CONFIG.invidious_companion.sample
|
||||||
|
|||||||
@ -40,8 +40,8 @@ private module Parsers
|
|||||||
begin
|
begin
|
||||||
return parse_internal(*args)
|
return parse_internal(*args)
|
||||||
rescue ex
|
rescue ex
|
||||||
LOGGER.debug("#{{{@type.name}}}: Failed to render item.")
|
LOGGER.debug("#{{{ @type.name }}}: Failed to render item.")
|
||||||
LOGGER.debug("#{{{@type.name}}}: Got exception: #{ex.message}")
|
LOGGER.debug("#{{{ @type.name }}}: Got exception: #{ex.message}")
|
||||||
ProblematicTimelineItem.new(
|
ProblematicTimelineItem.new(
|
||||||
parse_exception: ex
|
parse_exception: ex
|
||||||
)
|
)
|
||||||
@ -152,7 +152,6 @@ private module Parsers
|
|||||||
when "Premium"
|
when "Premium"
|
||||||
# TODO: Potentially available as item_contents["topStandaloneBadge"]["metadataBadgeRenderer"]
|
# TODO: Potentially available as item_contents["topStandaloneBadge"]["metadataBadgeRenderer"]
|
||||||
badges |= VideoBadges::Premium
|
badges |= VideoBadges::Premium
|
||||||
else nil # Ignore
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -173,7 +172,7 @@ private module Parsers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.parser_name
|
def self.parser_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -240,7 +239,7 @@ private module Parsers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.parser_name
|
def self.parser_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -289,7 +288,7 @@ private module Parsers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.parser_name
|
def self.parser_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -334,7 +333,7 @@ private module Parsers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.parser_name
|
def self.parser_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -395,7 +394,7 @@ private module Parsers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.parser_name
|
def self.parser_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -467,7 +466,7 @@ private module Parsers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.parser_name
|
def self.parser_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -496,7 +495,7 @@ private module Parsers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.parser_name
|
def self.parser_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -527,7 +526,7 @@ private module Parsers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.parser_name
|
def self.parser_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -626,7 +625,7 @@ private module Parsers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.parser_name
|
def self.parser_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -655,6 +654,10 @@ private module Parsers
|
|||||||
thumbnail_view_model = item_contents.dig(
|
thumbnail_view_model = item_contents.dig(
|
||||||
"contentImage", "thumbnailViewModel"
|
"contentImage", "thumbnailViewModel"
|
||||||
)
|
)
|
||||||
|
# TODO: This is an useless assignment, is not used anywhere
|
||||||
|
# so check if it can be used somewhere later.
|
||||||
|
#
|
||||||
|
# ameba:disable Lint/UselessAssign
|
||||||
thumbnail = thumbnail_view_model.dig("image", "sources", 0, "url").as_s
|
thumbnail = thumbnail_view_model.dig("image", "sources", 0, "url").as_s
|
||||||
|
|
||||||
video_id = item_contents["contentId"].as_s
|
video_id = item_contents["contentId"].as_s
|
||||||
@ -739,9 +742,9 @@ private module Parsers
|
|||||||
video_count = thumbnail_view_model.dig("overlays").as_a
|
video_count = thumbnail_view_model.dig("overlays").as_a
|
||||||
.compact_map(&.dig?("thumbnailOverlayBadgeViewModel", "thumbnailBadges").try &.as_a)
|
.compact_map(&.dig?("thumbnailOverlayBadgeViewModel", "thumbnailBadges").try &.as_a)
|
||||||
.flatten
|
.flatten
|
||||||
.find(nil, &.dig?("thumbnailBadgeViewModel", "text").try { |node|
|
.find(nil, &.dig?("thumbnailBadgeViewModel", "text").try do |node|
|
||||||
{"episodes", "videos", "lessons"}.any? { |str| node.as_s.ends_with?(str) }
|
{"episodes", "videos", "lessons"}.any? { |str| node.as_s.ends_with?(str) }
|
||||||
})
|
end)
|
||||||
.try &.dig("thumbnailBadgeViewModel", "text").as_s.to_i(strict: false)
|
.try &.dig("thumbnailBadgeViewModel", "text").as_s.to_i(strict: false)
|
||||||
|
|
||||||
metadata = item_contents.dig("metadata", "lockupMetadataViewModel")
|
metadata = item_contents.dig("metadata", "lockupMetadataViewModel")
|
||||||
@ -790,10 +793,10 @@ private module Parsers
|
|||||||
# ]
|
# ]
|
||||||
#
|
#
|
||||||
metadata_rows = metadata.dig?("metadata", "contentMetadataViewModel", "metadataRows").try &.as_a
|
metadata_rows = metadata.dig?("metadata", "contentMetadataViewModel", "metadataRows").try &.as_a
|
||||||
metadata_parts = metadata_rows.try &.find { |row|
|
metadata_parts = metadata_rows.try &.find do |row|
|
||||||
parts = row["metadataParts"]?.try &.as_a
|
parts = row["metadataParts"]?.try &.as_a
|
||||||
parts && !parts.any? { |item| item.dig?("text", "content").try &.as_s == "View full playlist" }
|
parts && !parts.any? { |item| item.dig?("text", "content").try &.as_s == "View full playlist" }
|
||||||
}.try &.["metadataParts"].as_a
|
end.try &.["metadataParts"].as_a
|
||||||
|
|
||||||
if author_info = metadata_parts.try &.find(&.dig?("text", "commandRuns"))
|
if author_info = metadata_parts.try &.find(&.dig?("text", "commandRuns"))
|
||||||
.try &.["text"]
|
.try &.["text"]
|
||||||
@ -831,7 +834,7 @@ private module Parsers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.parser_name
|
def self.parser_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -889,7 +892,7 @@ private module Parsers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.parser_name
|
def self.parser_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -918,7 +921,7 @@ private module Parsers
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.parser_name
|
def self.parser_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1005,7 +1008,7 @@ private module Extractors
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.extractor_name
|
def self.extractor_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1046,7 +1049,7 @@ private module Extractors
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.extractor_name
|
def self.extractor_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1080,7 +1083,7 @@ private module Extractors
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.extractor_name
|
def self.extractor_name
|
||||||
return {{@type.name}}
|
return {{ @type.name }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -17,15 +17,13 @@
|
|||||||
# another nil will be returned.
|
# another nil will be returned.
|
||||||
def extract_text(item : JSON::Any?) : String?
|
def extract_text(item : JSON::Any?) : String?
|
||||||
if item.nil?
|
if item.nil?
|
||||||
return nil
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if text_container = item["simpleText"]?
|
if text_container = item["simpleText"]?
|
||||||
return text_container.as_s
|
return text_container.as_s
|
||||||
elsif text_container = item["runs"]?
|
elsif text_container = item["runs"]?
|
||||||
return text_container.as_a.map(&.["text"].as_s).join("")
|
return text_container.as_a.map(&.["text"].as_s).join("")
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -46,7 +46,7 @@ module UrlSanitizer
|
|||||||
when "results", "search"
|
when "results", "search"
|
||||||
return :search
|
return :search
|
||||||
else # hashtag, post, trending, brand URLs, etc..
|
else # hashtag, post, trending, brand URLs, etc..
|
||||||
return nil
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -210,7 +210,7 @@ module YoutubeAPI
|
|||||||
|
|
||||||
# Region to provide to youtube, e.g to alter search results
|
# Region to provide to youtube, e.g to alter search results
|
||||||
# (this is passed as the `gl` parameter).
|
# (this is passed as the `gl` parameter).
|
||||||
property region : String | Nil
|
property region : String?
|
||||||
|
|
||||||
# Initialization function
|
# Initialization function
|
||||||
def initialize(
|
def initialize(
|
||||||
@ -286,7 +286,7 @@ module YoutubeAPI
|
|||||||
# Return, as a Hash, the "context" data required to request the
|
# Return, as a Hash, the "context" data required to request the
|
||||||
# youtube API endpoints.
|
# youtube API endpoints.
|
||||||
#
|
#
|
||||||
private def make_context(client_config : ClientConfig | Nil, video_id = "dQw4w9WgXcQ") : Hash
|
private def make_context(client_config : ClientConfig?, video_id = "dQw4w9WgXcQ") : Hash
|
||||||
# Use the default client config if nil is passed
|
# Use the default client config if nil is passed
|
||||||
client_config ||= DEFAULT_CLIENT_CONFIG
|
client_config ||= DEFAULT_CLIENT_CONFIG
|
||||||
|
|
||||||
@ -356,7 +356,7 @@ module YoutubeAPI
|
|||||||
#
|
#
|
||||||
# - A playlist ID (parameters MUST be an empty string)
|
# - A playlist ID (parameters MUST be an empty string)
|
||||||
#
|
#
|
||||||
def browse(continuation : String, client_config : ClientConfig | Nil = nil)
|
def browse(continuation : String, client_config : ClientConfig? = nil)
|
||||||
# JSON Request data, required by the API
|
# JSON Request data, required by the API
|
||||||
data = {
|
data = {
|
||||||
"context" => self.make_context(client_config),
|
"context" => self.make_context(client_config),
|
||||||
@ -371,7 +371,7 @@ module YoutubeAPI
|
|||||||
browse_id : String,
|
browse_id : String,
|
||||||
*, # Force the following parameters to be passed by name
|
*, # Force the following parameters to be passed by name
|
||||||
params : String,
|
params : String,
|
||||||
client_config : ClientConfig | Nil = nil,
|
client_config : ClientConfig? = nil,
|
||||||
)
|
)
|
||||||
# JSON Request data, required by the API
|
# JSON Request data, required by the API
|
||||||
data = {
|
data = {
|
||||||
@ -424,7 +424,7 @@ module YoutubeAPI
|
|||||||
# })
|
# })
|
||||||
# ```
|
# ```
|
||||||
#
|
#
|
||||||
def next(continuation : String, *, client_config : ClientConfig | Nil = nil)
|
def next(continuation : String, *, client_config : ClientConfig? = nil)
|
||||||
# JSON Request data, required by the API
|
# JSON Request data, required by the API
|
||||||
data = {
|
data = {
|
||||||
"context" => self.make_context(client_config),
|
"context" => self.make_context(client_config),
|
||||||
@ -435,7 +435,7 @@ module YoutubeAPI
|
|||||||
end
|
end
|
||||||
|
|
||||||
# :ditto:
|
# :ditto:
|
||||||
def next(data : Hash, *, client_config : ClientConfig | Nil = nil)
|
def next(data : Hash, *, client_config : ClientConfig? = nil)
|
||||||
# JSON Request data, required by the API
|
# JSON Request data, required by the API
|
||||||
data2 = data.merge({
|
data2 = data.merge({
|
||||||
"context" => self.make_context(client_config),
|
"context" => self.make_context(client_config),
|
||||||
@ -445,7 +445,7 @@ module YoutubeAPI
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Allow a NamedTuple to be passed, too.
|
# Allow a NamedTuple to be passed, too.
|
||||||
def next(data : NamedTuple, *, client_config : ClientConfig | Nil = nil)
|
def next(data : NamedTuple, *, client_config : ClientConfig? = nil)
|
||||||
return self.next(data.to_h, client_config: client_config)
|
return self.next(data.to_h, client_config: client_config)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -466,7 +466,7 @@ module YoutubeAPI
|
|||||||
if CONFIG.invidious_companion.present?
|
if CONFIG.invidious_companion.present?
|
||||||
return self._post_invidious_companion("/youtubei/v1/player", data)
|
return self._post_invidious_companion("/youtubei/v1/player", data)
|
||||||
else
|
else
|
||||||
return nil
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -498,7 +498,7 @@ module YoutubeAPI
|
|||||||
# channel_b = YoutubeAPI.resolve_url("https://www.youtube.com/c/invalid")
|
# channel_b = YoutubeAPI.resolve_url("https://www.youtube.com/c/invalid")
|
||||||
# ```
|
# ```
|
||||||
#
|
#
|
||||||
def resolve_url(url : String, client_config : ClientConfig | Nil = nil)
|
def resolve_url(url : String, client_config : ClientConfig? = nil)
|
||||||
data = {
|
data = {
|
||||||
"context" => self.make_context(nil),
|
"context" => self.make_context(nil),
|
||||||
"url" => url,
|
"url" => url,
|
||||||
@ -524,7 +524,7 @@ module YoutubeAPI
|
|||||||
def search(
|
def search(
|
||||||
search_query : String,
|
search_query : String,
|
||||||
params : String,
|
params : String,
|
||||||
client_config : ClientConfig | Nil = nil,
|
client_config : ClientConfig? = nil,
|
||||||
)
|
)
|
||||||
# JSON Request data, required by the API
|
# JSON Request data, required by the API
|
||||||
data = {
|
data = {
|
||||||
@ -550,7 +550,7 @@ module YoutubeAPI
|
|||||||
|
|
||||||
def get_transcript(
|
def get_transcript(
|
||||||
params : String,
|
params : String,
|
||||||
client_config : ClientConfig | Nil = nil,
|
client_config : ClientConfig? = nil,
|
||||||
) : Hash(String, JSON::Any)
|
) : Hash(String, JSON::Any)
|
||||||
data = {
|
data = {
|
||||||
"context" => self.make_context(client_config),
|
"context" => self.make_context(client_config),
|
||||||
@ -572,7 +572,7 @@ module YoutubeAPI
|
|||||||
def _post_json(
|
def _post_json(
|
||||||
endpoint : String,
|
endpoint : String,
|
||||||
data : Hash,
|
data : Hash,
|
||||||
client_config : ClientConfig | Nil,
|
client_config : ClientConfig?,
|
||||||
) : Hash(String, JSON::Any)
|
) : Hash(String, JSON::Any)
|
||||||
# Use the default client config if nil is passed
|
# Use the default client config if nil is passed
|
||||||
client_config ||= DEFAULT_CLIENT_CONFIG
|
client_config ||= DEFAULT_CLIENT_CONFIG
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user