summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md6
-rw-r--r--.github/workflows/build-nightly-container.yml13
-rw-r--r--.github/workflows/build-stable-container.yml13
-rw-r--r--.github/workflows/ci.yml6
-rw-r--r--CHANGELOG.md82
-rw-r--r--config/config.example.yml10
-rw-r--r--docker/Dockerfile6
-rw-r--r--docker/Dockerfile.arm649
-rw-r--r--shard.yml17
-rw-r--r--src/invidious/config.cr12
-rw-r--r--src/invidious/frontend/watch_page.cr2
-rw-r--r--src/invidious/helpers/errors.cr4
-rw-r--r--src/invidious/helpers/handlers.cr1
-rw-r--r--src/invidious/routes/api/manifest.cr10
-rw-r--r--src/invidious/routes/api/v1/channels.cr3
-rw-r--r--src/invidious/routes/api/v1/misc.cr4
-rw-r--r--src/invidious/routing.cr16
-rw-r--r--src/invidious/search/filters.cr2
-rw-r--r--src/invidious/search/query.cr2
-rw-r--r--src/invidious/videos.cr2
-rw-r--r--src/invidious/videos/parser.cr34
-rw-r--r--src/invidious/videos/storyboard.cr2
-rw-r--r--src/invidious/yt_backend/extractors.cr2
-rw-r--r--src/invidious/yt_backend/youtube_api.cr15
24 files changed, 165 insertions, 108 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 4c1a6330..02bc3795 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -10,8 +10,10 @@ assignees: ''
<!--
BEFORE TRYING TO REPORT A BUG:
- * Read the FAQ!
- * Use the search function to check if there is already an issue open for your problem!
+ * Read the FAQ: https://docs.invidious.io/faq/!
+ * Use the search function to check if there is already an issue open for your problem: https://github.com/search?q=repo%3Aiv-org%2Finvidious+replace+me+with+your+bug&type=issues!
+
+ MAKE SURE TO FOLLOW THE TWO STEPS ABOVE BEFORE REPORTING A BUG. A BUG THAT ALREADY EXIST WILL IMMEDIATELY CLOSED.
If you want to suggest a new feature please use "Feature request" instead
If you want to suggest an enhancement to an existing feature please use "Enhancement" instead
diff --git a/.github/workflows/build-nightly-container.yml b/.github/workflows/build-nightly-container.yml
index bee27600..5ff3322f 100644
--- a/.github/workflows/build-nightly-container.yml
+++ b/.github/workflows/build-nightly-container.yml
@@ -23,19 +23,6 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- - name: Install Crystal
- uses: crystal-lang/install-crystal@v1.8.2
- with:
- crystal: 1.12.2
-
- - name: Run lint
- run: |
- if ! crystal tool format --check; then
- crystal tool format
- git diff
- exit 1
- fi
-
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
diff --git a/.github/workflows/build-stable-container.yml b/.github/workflows/build-stable-container.yml
index d2d106b6..25571ed6 100644
--- a/.github/workflows/build-stable-container.yml
+++ b/.github/workflows/build-stable-container.yml
@@ -14,19 +14,6 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- - name: Install Crystal
- uses: crystal-lang/install-crystal@v1.8.2
- with:
- crystal: 1.12.2
-
- - name: Run lint
- run: |
- if ! crystal tool format --check; then
- crystal tool format
- git diff
- exit 1
- fi
-
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index dd472d1a..5f859613 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -38,11 +38,10 @@ jobs:
matrix:
stable: [true]
crystal:
- - 1.10.1
- - 1.11.2
- 1.12.1
- 1.13.2
- 1.14.0
+ - 1.15.0
include:
- crystal: nightly
stable: false
@@ -136,6 +135,7 @@ jobs:
submodules: true
- name: Install Crystal
+ id: lint_step_install_crystal
uses: crystal-lang/install-crystal@v1.8.0
with:
crystal: latest
@@ -146,7 +146,7 @@ jobs:
path: |
./lib
./bin
- key: shards-${{ hashFiles('shard.lock') }}
+ key: shards-${{ hashFiles('shard.lock') }}-${{ steps.lint_step_install_crystal.outputs.crystal }}
- name: Install Shards
run: |
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 061f977c..5af38003 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,8 +3,84 @@
## vX.Y.0 (future)
+## v2.20241110.0
+
+### Wrap-up
+
+This release is most importantly here to fix to the annoying "Youtube API returned error 400"
+error that prevented all channel pages from loading.
+
+If you're updating from the previous release, it provides no improvements on the ability to play
+videos. If updating from a commit in-between release, it removes the "Please sign in" error caused
+by a previous attempt at restoring video playback on large instances.
+
+In the preferences, a new option allows for control of video preload. When enabled, this option
+tells the browser to load the video as soon as the page is loaded (this used to be the default).
+When disabled, the video starts loading only when the "play" button is pressed.
+
+New interface languages available: Bulgarian, Welsh and Lombard
+
+New dependency required: `tzdata`.
+
+An HTTP proxy can be configured directly in Invidious, if needed. \
+**NOTE:** In that case, it is recommended to comment out `force_resolve`.
+
+
+### New features & important changes
+
+#### For users
+
+* Channels: Fix "Youtube API returned error 400" error preventing channel pages from loading
+* Channels: Shorts can now be sorted by "newest", "oldest" and "popular"
+* Preferences: Addition of the new "preload" option
+* New interface languages available: Bulgarian, Welsh and Lombard
+* Added "Filipino (auto-generated)" to the list of caption languages available
+* Lots of new translations from Weblate
+
+#### For instance owners
+
+* Allow the configuration of an HTTP proxy to talk to Youtube
+* Invidious tries to reconnect to `inv_sig_helper` if the socket is closed
+* The instance list is downloaded in the background to improve redirection speed
+* New `colorize_logs` option makes each log level a different color
+
+#### For developpers
+
+* `/api/v1/channels/{id}/shorts` now supports the `sort-by` parameter with the following values:
+ `newest`, `oldest` and `popular`
+* Older `/api/v1/channels/xyz/{id}` (tab name before UCID) were removed
+* API/Search: New video metadata available: `isNew`, `is4k`, `is8k`, `isVr180`, `isVr360`,
+ `is3d` and `hasCaptions`
+
+### Bugs fixed
+
+#### User-side
+
+* Channels: The second page of shorts now loads as expected
+* Channels: Fixed intermittent empty "playlists" tab
+* Search: Fixed `youtu.be` URLs not being properly redirected to the watch page
+* Fixed `DB::MappingException` error on the subscriptions feed (due to missing `tzdata` in docker)
+* Switching to another instance is much faster
+* Fixed an "invalid byte sequence" error when subscribing to a playlist
+* Videos: Playback URLs were sometimes broken when cached and `inv_sig_helper` was used
+
+#### For instance owners
+
+* Fix `force_resolve` being ignored in some cases
+
+#### API
+
+* API/Videos: Fixed `live_now` and `premiere_timestamp` sometimes not having the right values
+
+
### Full list of pull requests merged since the last release (newest first)
+* API: Add "sort_by" parameter to channels/shorts endpoint ([#5071], thanks @iBicha)
+* Docker: Install tzdata in Dockerfile ([#5070], by @SamantazFox)
+* Videos: Stop using TVHTML5_SIMPLY_EMBEDDED_PLAYER ([#5063], thanks @unixfox)
+* Routing: Deprecate old channel API routes ([#5045], by @SamantazFox)
+* Videos: use WEB client instead of WEB CREATOR ([#4984], thanks @unixfox)
+* Parsers: Fix parsing live_now and premiere_timestamp ([#4934], thanks @absidue)
* Stale bot updates ([#5060], thanks @syeopite)
* Channels: Fix "Youtube API returned error 400" ([#5059], by @SamantazFox)
* Channels: Fix for live videos ([#5027], thanks @iBicha)
@@ -52,15 +128,21 @@
[#4928]: https://github.com/iv-org/invidious/pull/4928
[#4930]: https://github.com/iv-org/invidious/pull/4930
[#4931]: https://github.com/iv-org/invidious/pull/4931
+[#4934]: https://github.com/iv-org/invidious/pull/4934
[#4942]: https://github.com/iv-org/invidious/pull/4942
+[#4984]: https://github.com/iv-org/invidious/pull/4984
[#4991]: https://github.com/iv-org/invidious/pull/4991
[#4993]: https://github.com/iv-org/invidious/pull/4993
[#4995]: https://github.com/iv-org/invidious/pull/4995
[#5027]: https://github.com/iv-org/invidious/pull/5027
[#5034]: https://github.com/iv-org/invidious/pull/5034
+[#5045]: https://github.com/iv-org/invidious/pull/5045
[#5046]: https://github.com/iv-org/invidious/pull/5046
[#5059]: https://github.com/iv-org/invidious/pull/5059
[#5060]: https://github.com/iv-org/invidious/pull/5060
+[#5063]: https://github.com/iv-org/invidious/pull/5063
+[#5070]: https://github.com/iv-org/invidious/pull/5070
+[#5071]: https://github.com/iv-org/invidious/pull/5071
## v2.20240825.2 (2024-08-26)
diff --git a/config/config.example.yml b/config/config.example.yml
index a3a2eeb7..bc2deda5 100644
--- a/config/config.example.yml
+++ b/config/config.example.yml
@@ -178,11 +178,11 @@ https_only: false
##
## If unset, then no HTTP proxy will be used.
##
-http_proxy:
- user:
- password:
- host:
- port:
+#http_proxy:
+# user:
+# password:
+# host:
+# port:
##
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 3d9323fd..900c9e74 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -1,4 +1,4 @@
-FROM crystallang/crystal:1.12.1-alpine AS builder
+FROM crystallang/crystal:1.12.2-alpine AS builder
RUN apk add --no-cache sqlite-static yaml-static
@@ -32,8 +32,8 @@ RUN if [[ "${release}" == 1 ]] ; then \
--link-flags "-lxml2 -llzma"; \
fi
-FROM alpine:3.18
-RUN apk add --no-cache rsvg-convert ttf-opensans tini
+FROM alpine:3.20
+RUN apk add --no-cache rsvg-convert ttf-opensans tini tzdata
WORKDIR /invidious
RUN addgroup -g 1000 -S invidious && \
adduser -u 1000 -S invidious -G invidious
diff --git a/docker/Dockerfile.arm64 b/docker/Dockerfile.arm64
index f054b326..ce9bab08 100644
--- a/docker/Dockerfile.arm64
+++ b/docker/Dockerfile.arm64
@@ -1,5 +1,6 @@
-FROM alpine:3.19 AS builder
-RUN apk add --no-cache 'crystal=1.10.1-r0' shards sqlite-static yaml-static yaml-dev libxml2-static zlib-static openssl-libs-static openssl-dev musl-dev xz-static
+FROM alpine:3.20 AS builder
+RUN apk add --no-cache 'crystal=1.12.2-r0' shards sqlite-static yaml-static yaml-dev libxml2-static \
+ zlib-static openssl-libs-static openssl-dev musl-dev xz-static
ARG release
@@ -32,8 +33,8 @@ RUN if [[ "${release}" == 1 ]] ; then \
--link-flags "-lxml2 -llzma"; \
fi
-FROM alpine:3.18
-RUN apk add --no-cache rsvg-convert ttf-opensans tini
+FROM alpine:3.20
+RUN apk add --no-cache rsvg-convert ttf-opensans tini tzdata
WORKDIR /invidious
RUN addgroup -g 1000 -S invidious && \
adduser -u 1000 -S invidious -G invidious
diff --git a/shard.yml b/shard.yml
index 513e5db3..af7e4186 100644
--- a/shard.yml
+++ b/shard.yml
@@ -1,13 +1,12 @@
name: invidious
-version: 0.20.1
+version: 2.20241110.0-dev
authors:
- - Omar Roth <omarroth@protonmail.com>
- - Invidious team
+ - Invidious team <contact@invidious.io>
+ - Contributors!
-targets:
- invidious:
- main: src/invidious.cr
+description: |
+ Invidious is an alternative front-end to YouTube
dependencies:
pg:
@@ -40,6 +39,10 @@ development_dependencies:
github: crystal-ameba/ameba
version: ~> 1.6.1
-crystal: ">= 1.0.0, < 2.0.0"
+crystal: ">= 1.10.0, < 2.0.0"
license: AGPLv3
+
+repository: https://github.com/iv-org/invidious
+homepage: https://invidious.io
+documentation: https://docs.invidious.io
diff --git a/src/invidious/config.cr b/src/invidious/config.cr
index c4ca622f..4b3bdafc 100644
--- a/src/invidious/config.cr
+++ b/src/invidious/config.cr
@@ -184,6 +184,9 @@ class Config
config = Config.from_yaml(config_yaml)
# Update config from env vars (upcased and prefixed with "INVIDIOUS_")
+ #
+ # Also checks if any top-level config options are set to "CHANGE_ME!!"
+ # TODO: Support non-top-level config options such as the ones in DBConfig
{% for ivar in Config.instance_vars %}
{% env_id = "INVIDIOUS_#{ivar.id.upcase}" %}
@@ -220,6 +223,12 @@ class Config
exit(1)
end
end
+
+ # Warn when any config attribute is set to "CHANGE_ME!!"
+ if config.{{ivar.id}} == "CHANGE_ME!!"
+ puts "Config: The value of '#{ {{ivar.stringify}} }' needs to be changed!!"
+ exit(1)
+ end
{% end %}
# HMAC_key is mandatory
@@ -227,9 +236,6 @@ class Config
if config.hmac_key.empty?
puts "Config: 'hmac_key' is required/can't be empty"
exit(1)
- elsif config.hmac_key == "CHANGE_ME!!"
- puts "Config: The value of 'hmac_key' needs to be changed!!"
- exit(1)
end
# Build database_url from db.* if it's not set directly
diff --git a/src/invidious/frontend/watch_page.cr b/src/invidious/frontend/watch_page.cr
index c8cb7110..2e2f6ad0 100644
--- a/src/invidious/frontend/watch_page.cr
+++ b/src/invidious/frontend/watch_page.cr
@@ -13,7 +13,7 @@ module Invidious::Frontend::WatchPage
@full_videos,
@video_streams,
@audio_streams,
- @captions
+ @captions,
)
end
end
diff --git a/src/invidious/helpers/errors.cr b/src/invidious/helpers/errors.cr
index b7643194..900cb0c6 100644
--- a/src/invidious/helpers/errors.cr
+++ b/src/invidious/helpers/errors.cr
@@ -130,7 +130,7 @@ def error_json_helper(
env : HTTP::Server::Context,
status_code : Int32,
exception : Exception,
- additional_fields : Hash(String, Object) | Nil = nil
+ additional_fields : Hash(String, Object) | Nil = nil,
)
if exception.is_a?(InfoException)
return error_json_helper(env, status_code, exception.message || "", additional_fields)
@@ -152,7 +152,7 @@ def error_json_helper(
env : HTTP::Server::Context,
status_code : Int32,
message : String,
- additional_fields : Hash(String, Object) | Nil = nil
+ additional_fields : Hash(String, Object) | Nil = nil,
)
env.response.content_type = "application/json"
env.response.status_code = status_code
diff --git a/src/invidious/helpers/handlers.cr b/src/invidious/helpers/handlers.cr
index f3e3b951..13ea9fe9 100644
--- a/src/invidious/helpers/handlers.cr
+++ b/src/invidious/helpers/handlers.cr
@@ -27,6 +27,7 @@ class Kemal::RouteHandler
# Processes the route if it's a match. Otherwise renders 404.
private def process_request(context)
raise Kemal::Exceptions::RouteNotFound.new(context) unless context.route_found?
+ return if context.response.closed?
content = context.route.handler.call(context)
if !Kemal.config.error_handlers.empty? && Kemal.config.error_handlers.has_key?(context.response.status_code) && exclude_match?(context)
diff --git a/src/invidious/routes/api/manifest.cr b/src/invidious/routes/api/manifest.cr
index d89e752c..78b4906d 100644
--- a/src/invidious/routes/api/manifest.cr
+++ b/src/invidious/routes/api/manifest.cr
@@ -70,17 +70,23 @@ module Invidious::Routes::API::Manifest
# OTF streams aren't supported yet (See https://github.com/TeamNewPipe/NewPipe/issues/2415)
next if !(fmt.has_key?("indexRange") && fmt.has_key?("initRange"))
+ audio_track = fmt["audioTrack"]?.try &.as_h? || {} of String => JSON::Any
+ lang = audio_track["id"]?.try &.as_s.split('.')[0] || "und"
+ is_default = audio_track.has_key?("audioIsDefault") ? audio_track["audioIsDefault"].as_bool : i == 0
+ displayname = audio_track["displayName"]?.try &.as_s || "Unknown"
+ bitrate = fmt["bitrate"]
+
# Different representations of the same audio should be groupped into one AdaptationSet.
# However, most players don't support auto quality switching, so we have to trick them
# into providing a quality selector.
# See https://github.com/iv-org/invidious/issues/3074 for more details.
- xml.element("AdaptationSet", id: i, mimeType: mime_type, startWithSAP: 1, subsegmentAlignment: true, label: fmt["bitrate"].to_s + "k") do
+ xml.element("AdaptationSet", id: i, mimeType: mime_type, startWithSAP: 1, subsegmentAlignment: true, label: "#{displayname} [#{bitrate}k]", lang: lang) do
codecs = fmt["mimeType"].as_s.split("codecs=")[1].strip('"')
bandwidth = fmt["bitrate"].as_i
itag = fmt["itag"].as_i
url = fmt["url"].as_s
- xml.element("Role", schemeIdUri: "urn:mpeg:dash:role:2011", value: i == 0 ? "main" : "alternate")
+ xml.element("Role", schemeIdUri: "urn:mpeg:dash:role:2011", value: is_default ? "main" : "alternate")
xml.element("Representation", id: fmt["itag"], codecs: codecs, bandwidth: bandwidth) do
xml.element("AudioChannelConfiguration", schemeIdUri: "urn:mpeg:dash:23003:3:audio_channel_configuration:2011",
diff --git a/src/invidious/routes/api/v1/channels.cr b/src/invidious/routes/api/v1/channels.cr
index 2da76134..588bbc2a 100644
--- a/src/invidious/routes/api/v1/channels.cr
+++ b/src/invidious/routes/api/v1/channels.cr
@@ -197,6 +197,7 @@ module Invidious::Routes::API::V1::Channels
get_channel()
# Retrieve continuation from URL parameters
+ sort_by = env.params.query["sort_by"]?.try &.downcase || "newest"
continuation = env.params.query["continuation"]?
if channel.is_age_gated
@@ -211,7 +212,7 @@ module Invidious::Routes::API::V1::Channels
else
begin
videos, next_continuation = Channel::Tabs.get_shorts(
- channel, continuation: continuation
+ channel, continuation: continuation, sort_by: sort_by
)
rescue ex
return error_json(500, ex)
diff --git a/src/invidious/routes/api/v1/misc.cr b/src/invidious/routes/api/v1/misc.cr
index 093669fe..94a7e9b6 100644
--- a/src/invidious/routes/api/v1/misc.cr
+++ b/src/invidious/routes/api/v1/misc.cr
@@ -141,9 +141,7 @@ module Invidious::Routes::API::V1::Misc
json.field "authorUrl", "/channel/#{video.ucid}"
json.field "videoThumbnails" do
- json.array do
- Invidious::JSONify::APIv1.thumbnails(json, video.id)
- end
+ Invidious::JSONify::APIv1.thumbnails(json, video.id)
end
json.field "index", video.index
diff --git a/src/invidious/routing.cr b/src/invidious/routing.cr
index ba05da19..9009062f 100644
--- a/src/invidious/routing.cr
+++ b/src/invidious/routing.cr
@@ -243,17 +243,16 @@ module Invidious::Routing
# Channels
get "/api/v1/channels/:ucid", {{namespace}}::Channels, :home
+ get "/api/v1/channels/:ucid/latest", {{namespace}}::Channels, :latest
+ get "/api/v1/channels/:ucid/videos", {{namespace}}::Channels, :videos
get "/api/v1/channels/:ucid/shorts", {{namespace}}::Channels, :shorts
get "/api/v1/channels/:ucid/streams", {{namespace}}::Channels, :streams
get "/api/v1/channels/:ucid/podcasts", {{namespace}}::Channels, :podcasts
get "/api/v1/channels/:ucid/releases", {{namespace}}::Channels, :releases
-
+ get "/api/v1/channels/:ucid/playlists", {{namespace}}::Channels, :playlists
+ get "/api/v1/channels/:ucid/community", {{namespace}}::Channels, :community
get "/api/v1/channels/:ucid/channels", {{namespace}}::Channels, :channels
-
- {% for route in {"videos", "latest", "playlists", "community", "search"} %}
- get "/api/v1/channels/#{{{route}}}/:ucid", {{namespace}}::Channels, :{{route}}
- get "/api/v1/channels/:ucid/#{{{route}}}", {{namespace}}::Channels, :{{route}}
- {% end %}
+ get "/api/v1/channels/:ucid/search", {{namespace}}::Channels, :search
# Posts
get "/api/v1/post/:id", {{namespace}}::Channels, :post
@@ -271,11 +270,6 @@ module Invidious::Routing
# Authenticated
- # The notification APIs cannot be extracted yet! They require the *local* notifications constant defined in invidious.cr
- #
- # Invidious::Routing.get "/api/v1/auth/notifications", {{namespace}}::Authenticated, :notifications
- # Invidious::Routing.post "/api/v1/auth/notifications", {{namespace}}::Authenticated, :notifications
-
get "/api/v1/auth/preferences", {{namespace}}::Authenticated, :get_preferences
post "/api/v1/auth/preferences", {{namespace}}::Authenticated, :set_preferences
diff --git a/src/invidious/search/filters.cr b/src/invidious/search/filters.cr
index bf968734..bc2715cf 100644
--- a/src/invidious/search/filters.cr
+++ b/src/invidious/search/filters.cr
@@ -75,7 +75,7 @@ module Invidious::Search
@type : Type = Type::All,
@duration : Duration = Duration::None,
@features : Features = Features::None,
- @sort : Sort = Sort::Relevance
+ @sort : Sort = Sort::Relevance,
)
end
diff --git a/src/invidious/search/query.cr b/src/invidious/search/query.cr
index c8e8cf7f..94a92e23 100644
--- a/src/invidious/search/query.cr
+++ b/src/invidious/search/query.cr
@@ -47,7 +47,7 @@ module Invidious::Search
def initialize(
params : HTTP::Params,
@type : Type = Type::Regular,
- @region : String? = nil
+ @region : String? = nil,
)
# Get the raw search query string (common to all search types). In
# Regular search mode, also look for the `search_query` URL parameter
diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr
index ae09e736..962f87bd 100644
--- a/src/invidious/videos.cr
+++ b/src/invidious/videos.cr
@@ -106,7 +106,7 @@ struct Video
if formats = info.dig?("streamingData", "adaptiveFormats")
return formats
.as_a.map(&.as_h)
- .sort_by! { |f| f["width"]?.try &.as_i || 0 }
+ .sort_by! { |f| f["width"]?.try &.as_i || f["audioTrack"]?.try { |a| a["audioIsDefault"]?.try { |v| v.as_bool ? -1 : 0 } } || 0 }
else
return [] of Hash(String, JSON::Any)
end
diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr
index fb8935d9..915c9baf 100644
--- a/src/invidious/videos/parser.cr
+++ b/src/invidious/videos/parser.cr
@@ -53,10 +53,6 @@ end
def extract_video_info(video_id : String)
# Init client config for the API
client_config = YoutubeAPI::ClientConfig.new
- # Use the WEB_CREATOR when po_token is configured because it fully only works on this client
- if CONFIG.po_token
- client_config.client_type = YoutubeAPI::ClientType::WebCreator
- end
# Fetch data from the player endpoint
player_response = YoutubeAPI.player(video_id: video_id, params: "2AMB", client_config: client_config)
@@ -106,15 +102,8 @@ def extract_video_info(video_id : String)
new_player_response = nil
- # Second try in case WEB_CREATOR doesn't work with po_token.
- # Only trigger if reason found and po_token configured.
- if reason && CONFIG.po_token
- client_config.client_type = YoutubeAPI::ClientType::WebEmbeddedPlayer
- new_player_response = try_fetch_streaming_data(video_id, client_config)
- end
-
- # Don't use Android client if po_token is passed because po_token doesn't
- # work for Android client.
+ # Don't use Android test suite client if po_token is passed because po_token doesn't
+ # work for Android test suite client.
if reason.nil? && CONFIG.po_token.nil?
# Fetch the video streams using an Android client in order to get the
# decrypted URLs and maybe fix throttling issues (#2194). See the
@@ -124,14 +113,6 @@ def extract_video_info(video_id : String)
new_player_response = try_fetch_streaming_data(video_id, client_config)
end
- # Last hope
- # Only trigger if reason found or didn't work wth Android client.
- # TvHtml5ScreenEmbed now requires sig helper for it to work but doesn't work with po_token.
- if reason && CONFIG.po_token.nil?
- client_config.client_type = YoutubeAPI::ClientType::TvHtml5ScreenEmbed
- new_player_response = try_fetch_streaming_data(video_id, client_config)
- end
-
# Replace player response and reset reason
if !new_player_response.nil?
# Preserve captions & storyboard data before replacement
@@ -235,8 +216,17 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any
premiere_timestamp = microformat.dig?("liveBroadcastDetails", "startTimestamp")
.try { |t| Time.parse_rfc3339(t.as_s) }
+ premiere_timestamp ||= player_response.dig?(
+ "playabilityStatus", "liveStreamability",
+ "liveStreamabilityRenderer", "offlineSlate",
+ "liveStreamOfflineSlateRenderer", "scheduledStartTime"
+ )
+ .try &.as_s.to_i64
+ .try { |t| Time.unix(t) }
+
live_now = microformat.dig?("liveBroadcastDetails", "isLiveNow")
- .try &.as_bool || false
+ .try &.as_bool
+ live_now ||= video_details.dig?("isLive").try &.as_bool || false
post_live_dvr = video_details.dig?("isPostLiveDvr")
.try &.as_bool || false
diff --git a/src/invidious/videos/storyboard.cr b/src/invidious/videos/storyboard.cr
index a72c2f55..bd0eef59 100644
--- a/src/invidious/videos/storyboard.cr
+++ b/src/invidious/videos/storyboard.cr
@@ -20,7 +20,7 @@ module Invidious::Videos
def initialize(
*, @url, @width, @height, @count, @interval,
- @rows, @columns, @images_count
+ @rows, @columns, @images_count,
)
authority = /(i\d?).ytimg.com/.match!(@url.host.not_nil!)[1]?
diff --git a/src/invidious/yt_backend/extractors.cr b/src/invidious/yt_backend/extractors.cr
index a28e1df6..edd7bf1b 100644
--- a/src/invidious/yt_backend/extractors.cr
+++ b/src/invidious/yt_backend/extractors.cr
@@ -1029,7 +1029,7 @@ end
def extract_items(
initial_data : InitialData,
author_fallback : String? = nil,
- author_id_fallback : String? = nil
+ author_id_fallback : String? = nil,
) : {Array(SearchItem), String?}
items = [] of SearchItem
continuation = nil
diff --git a/src/invidious/yt_backend/youtube_api.cr b/src/invidious/yt_backend/youtube_api.cr
index e0a3181f..ec080d8c 100644
--- a/src/invidious/yt_backend/youtube_api.cr
+++ b/src/invidious/yt_backend/youtube_api.cr
@@ -211,7 +211,7 @@ module YoutubeAPI
def initialize(
*,
@client_type = ClientType::Web,
- @region = "US"
+ @region = "US",
)
end
@@ -300,9 +300,8 @@ module YoutubeAPI
end
if client_config.screen == "EMBED"
- # embedUrl https://www.google.com allow loading almost all video that are configured not embeddable
client_context["thirdParty"] = {
- "embedUrl" => "https://www.google.com/",
+ "embedUrl" => "https://www.youtube.com/embed/#{video_id}",
} of String => String | Int64
end
@@ -371,7 +370,7 @@ module YoutubeAPI
browse_id : String,
*, # Force the following parameters to be passed by name
params : String,
- client_config : ClientConfig | Nil = nil
+ client_config : ClientConfig | Nil = nil,
)
# JSON Request data, required by the API
data = {
@@ -465,7 +464,7 @@ module YoutubeAPI
video_id : String,
*, # Force the following parameters to be passed by name
params : String,
- client_config : ClientConfig | Nil = nil
+ client_config : ClientConfig | Nil = nil,
)
# Playback context, separate because it can be different between clients
playback_ctx = {
@@ -558,7 +557,7 @@ module YoutubeAPI
def search(
search_query : String,
params : String,
- client_config : ClientConfig | Nil = nil
+ client_config : ClientConfig | Nil = nil,
)
# JSON Request data, required by the API
data = {
@@ -584,7 +583,7 @@ module YoutubeAPI
def get_transcript(
params : String,
- client_config : ClientConfig | Nil = nil
+ client_config : ClientConfig | Nil = nil,
) : Hash(String, JSON::Any)
data = {
"context" => self.make_context(client_config),
@@ -606,7 +605,7 @@ module YoutubeAPI
def _post_json(
endpoint : String,
data : Hash,
- client_config : ClientConfig | Nil
+ client_config : ClientConfig | Nil,
) : Hash(String, JSON::Any)
# Use the default client config if nil is passed
client_config ||= DEFAULT_CLIENT_CONFIG