From 73bf956af5ff2595c4840397924127e7cf329598 Mon Sep 17 00:00:00 2001
From: epicsam123 <92618898+epicsam123@users.noreply.github.com>
Date: Wed, 19 Feb 2025 21:08:45 -0500
Subject: [PATCH 01/44] captions: provide "w", "o", "-", "+" keydowns for
player from YT
---
assets/css/player.css | 18 +++++++++++++++---
assets/js/player.js | 38 ++++++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+), 3 deletions(-)
diff --git a/assets/css/player.css b/assets/css/player.css
index 9cb400ad..028d5631 100644
--- a/assets/css/player.css
+++ b/assets/css/player.css
@@ -71,8 +71,10 @@
padding-top: 2em
}
-.video-js.player-style-youtube .vjs-progress-control .vjs-progress-holder, .video-js.player-style-youtube .vjs-progress-control {height: 5px;
-margin-bottom: 10px;}
+.video-js.player-style-youtube .vjs-progress-control .vjs-progress-holder, .video-js.player-style-youtube .vjs-progress-control {
+ height: 5px;
+ margin-bottom: 10px;
+}
ul.vjs-menu-content::-webkit-scrollbar {
display: none;
@@ -82,10 +84,20 @@ ul.vjs-menu-content::-webkit-scrollbar {
cursor: none;
}
+/* Customizable CSS in player.js */
+.vjs-text-track-display > div > div
+{
+ background-color: rgba(0, 0, 0, 0); /* caption window background: toggle with "w" event */
+}
+
+/* Customizable CSS in player.js */
.video-js .vjs-text-track-display > div > div > div {
- background-color: rgba(0, 0, 0, 0.75) !important;
+ font-size: 27px !important; /* Toggle with "-/=" event */
+ background-color: rgba(0, 0, 0, 0.75) !important; /* caption background: toggle with "w" event */
+ color: rgb(255, 255, 255, 1) !important; /* caption text: toggle with "o" event */
border-radius: 9px !important;
padding: 5px !important;
+ line-height: 1.5 !important;
}
.vjs-play-control,
diff --git a/assets/js/player.js b/assets/js/player.js
index 353a5296..c74a68a4 100644
--- a/assets/js/player.js
+++ b/assets/js/player.js
@@ -2,9 +2,16 @@
var player_data = JSON.parse(document.getElementById('player_data').textContent);
var video_data = JSON.parse(document.getElementById('video_data').textContent);
+var player_css = [...Array.from(document.styleSheets).find(sS => sS.href?.includes('player.css')).cssRules]
+var caption_background_css = player_css.find(rule => rule.selectorText === '.vjs-text-track-display > div > div');
+var caption_text_css = player_css.find(rule => rule.selectorText === '.video-js .vjs-text-track-display > div > div > div');
+
var options = {
liveui: true,
playbackRates: [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0],
+ captionSizes: ['22px', '27px', '32px', '37px'],
+ captionBackground: [0, 0.5, 0.8, 1].map(a => 'rgba(0, 0, 0, ' + a + ')'),
+ captionOpacity: [0.4, 0.7, 1].map(a => 'rgba(255, 255, 255, ' + a + ')'),
controlBar: {
children: [
'playToggle',
@@ -591,6 +598,31 @@ function increase_playback_rate(steps) {
player.playbackRate(options.playbackRates[newIndex]);
}
+function increase_caption_size(steps) {
+ const maxIndex = options.captionSizes.length - 1;
+ const font_size = caption_text_css.style.getPropertyValue('font-size');
+ const curIndex = options.captionSizes.indexOf(font_size);
+ let newIndex = curIndex + steps;
+ newIndex = helpers.clamp(newIndex, 0, maxIndex);
+ caption_text_css.style.setProperty('font-size', options.captionSizes[newIndex], 'important');
+}
+
+function toggle_caption_window() {
+ const numOptions = options.captionBackground.length;
+ const backgroundColor = caption_background_css.style.getPropertyValue('background-color');
+ const curIndex = options.captionBackground.indexOf(backgroundColor);
+ const newIndex = (curIndex + 1) % numOptions;
+ caption_background_css.style.setProperty('background-color', options.captionBackground[newIndex], 'important');
+}
+
+function toggle_caption_opacity() {
+ const numOptions = options.captionOpacity.length;
+ const opacity = caption_text_css.style.getPropertyValue('color');
+ const curIndex = options.captionOpacity.indexOf(opacity);
+ const newIndex = (curIndex + 1) % numOptions;
+ caption_text_css.style.setProperty('color', options.captionOpacity[newIndex], 'important');
+}
+
addEventListener('keydown', function (e) {
if (e.target.tagName.toLowerCase() === 'input') {
// Ignore input when focus is on certain elements, e.g. form fields.
@@ -686,6 +718,12 @@ addEventListener('keydown', function (e) {
case '>': action = increase_playback_rate.bind(this, 1); break;
case '<': action = increase_playback_rate.bind(this, -1); break;
+
+ case '=': action = increase_caption_size.bind(this, 1); break;
+ case '-': action = increase_caption_size.bind(this, -1); break;
+
+ case 'w': action = toggle_caption_window; break;
+ case 'o': action = toggle_caption_opacity; break;
default:
console.info('Unhandled key down event: %s:', decoratedKey, e);
From bc3b3f6d69977e799f4d4e99d5c0283916d0ca83 Mon Sep 17 00:00:00 2001
From: epicsam123 <92618898+epicsam123@users.noreply.github.com>
Date: Thu, 20 Mar 2025 10:09:43 -0400
Subject: [PATCH 02/44] updated caption features to use videojs interface
---
assets/css/player.css | 11 +--------
assets/js/player.js | 52 ++++++++++++++++++++++++-------------------
2 files changed, 30 insertions(+), 33 deletions(-)
diff --git a/assets/css/player.css b/assets/css/player.css
index 028d5631..60f3ce73 100644
--- a/assets/css/player.css
+++ b/assets/css/player.css
@@ -84,17 +84,8 @@ ul.vjs-menu-content::-webkit-scrollbar {
cursor: none;
}
-/* Customizable CSS in player.js */
-.vjs-text-track-display > div > div
-{
- background-color: rgba(0, 0, 0, 0); /* caption window background: toggle with "w" event */
-}
-
-/* Customizable CSS in player.js */
.video-js .vjs-text-track-display > div > div > div {
- font-size: 27px !important; /* Toggle with "-/=" event */
- background-color: rgba(0, 0, 0, 0.75) !important; /* caption background: toggle with "w" event */
- color: rgb(255, 255, 255, 1) !important; /* caption text: toggle with "o" event */
+ background-color: rgba(0, 0, 0, 0.75) !important;
border-radius: 9px !important;
padding: 5px !important;
line-height: 1.5 !important;
diff --git a/assets/js/player.js b/assets/js/player.js
index c74a68a4..dce432cb 100644
--- a/assets/js/player.js
+++ b/assets/js/player.js
@@ -2,16 +2,12 @@
var player_data = JSON.parse(document.getElementById('player_data').textContent);
var video_data = JSON.parse(document.getElementById('video_data').textContent);
-var player_css = [...Array.from(document.styleSheets).find(sS => sS.href?.includes('player.css')).cssRules]
-var caption_background_css = player_css.find(rule => rule.selectorText === '.vjs-text-track-display > div > div');
-var caption_text_css = player_css.find(rule => rule.selectorText === '.video-js .vjs-text-track-display > div > div > div');
-
var options = {
liveui: true,
playbackRates: [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0],
- captionSizes: ['22px', '27px', '32px', '37px'],
- captionBackground: [0, 0.5, 0.8, 1].map(a => 'rgba(0, 0, 0, ' + a + ')'),
- captionOpacity: [0.4, 0.7, 1].map(a => 'rgba(255, 255, 255, ' + a + ')'),
+ fontPercent: [0.5, 0.75, 1.25, 1.5, 1.75, 2, 3, 4],
+ windowOpacity: ['0', '0.5', '1'],
+ textOpacity: ['0.5', '1'],
controlBar: {
children: [
'playToggle',
@@ -543,9 +539,9 @@ const toggle_captions = (function () {
bindChange('off');
track.mode = mode;
setTimeout(function () {
- bindChange('on');
+ bindChange('on');
}, 0);
- }
+ }
bindChange('on');
return function () {
@@ -586,6 +582,13 @@ const toggle_captions = (function () {
};
})();
+// For real-time updates to captions (if currently showing)
+function update_captions() {
+ if (document.body.querySelector('.vjs-text-track-cue')) {
+ toggle_captions(); toggle_captions();
+ }
+}
+
function toggle_fullscreen() {
player.isFullscreen() ? player.exitFullscreen() : player.requestFullscreen();
}
@@ -599,28 +602,31 @@ function increase_playback_rate(steps) {
}
function increase_caption_size(steps) {
- const maxIndex = options.captionSizes.length - 1;
- const font_size = caption_text_css.style.getPropertyValue('font-size');
- const curIndex = options.captionSizes.indexOf(font_size);
+ const maxIndex = options.fontPercent.length - 1;
+ const fontPercent = player.textTrackSettings.getValues().fontPercent || 1.25;
+ const curIndex = options.fontPercent.indexOf(fontPercent);
let newIndex = curIndex + steps;
newIndex = helpers.clamp(newIndex, 0, maxIndex);
- caption_text_css.style.setProperty('font-size', options.captionSizes[newIndex], 'important');
+ player.textTrackSettings.setValues({ fontPercent: options.fontPercent[newIndex] });
+ update_captions();
}
function toggle_caption_window() {
- const numOptions = options.captionBackground.length;
- const backgroundColor = caption_background_css.style.getPropertyValue('background-color');
- const curIndex = options.captionBackground.indexOf(backgroundColor);
+ const numOptions = options.windowOpacity.length;
+ const windowOpacity = player.textTrackSettings.getValues().windowOpacity || '0';
+ const curIndex = options.windowOpacity.indexOf(windowOpacity);
const newIndex = (curIndex + 1) % numOptions;
- caption_background_css.style.setProperty('background-color', options.captionBackground[newIndex], 'important');
+ player.textTrackSettings.setValues({ windowOpacity: options.windowOpacity[newIndex] });
+ update_captions();
}
-
-function toggle_caption_opacity() {
- const numOptions = options.captionOpacity.length;
- const opacity = caption_text_css.style.getPropertyValue('color');
- const curIndex = options.captionOpacity.indexOf(opacity);
+
+ function toggle_caption_opacity() {
+ const numOptions = options.textOpacity.length;
+ const textOpacity = player.textTrackSettings.getValues().textOpacity || '1';
+ const curIndex = options.textOpacity.indexOf(textOpacity);
const newIndex = (curIndex + 1) % numOptions;
- caption_text_css.style.setProperty('color', options.captionOpacity[newIndex], 'important');
+ player.textTrackSettings.setValues({ textOpacity: options.textOpacity[newIndex] });
+ update_captions();
}
addEventListener('keydown', function (e) {
From e67a30b124debf30363e5e576f089b26c46f7c93 Mon Sep 17 00:00:00 2001
From: epicsam123 <92618898+epicsam123@users.noreply.github.com>
Date: Thu, 20 Mar 2025 10:29:26 -0400
Subject: [PATCH 03/44] formatting
---
assets/js/player.js | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/assets/js/player.js b/assets/js/player.js
index dce432cb..d6f2ec64 100644
--- a/assets/js/player.js
+++ b/assets/js/player.js
@@ -539,9 +539,9 @@ const toggle_captions = (function () {
bindChange('off');
track.mode = mode;
setTimeout(function () {
- bindChange('on');
+ bindChange('on');
}, 0);
- }
+ }
bindChange('on');
return function () {
@@ -584,9 +584,9 @@ const toggle_captions = (function () {
// For real-time updates to captions (if currently showing)
function update_captions() {
- if (document.body.querySelector('.vjs-text-track-cue')) {
- toggle_captions(); toggle_captions();
- }
+ if (document.body.querySelector('.vjs-text-track-cue')) {
+ toggle_captions(); toggle_captions();
+ }
}
function toggle_fullscreen() {
@@ -620,7 +620,7 @@ function toggle_caption_window() {
update_captions();
}
- function toggle_caption_opacity() {
+function toggle_caption_opacity() {
const numOptions = options.textOpacity.length;
const textOpacity = player.textTrackSettings.getValues().textOpacity || '1';
const curIndex = options.textOpacity.indexOf(textOpacity);
From bef2d7b6b515bc90d8a58e3fa9776ab52fc48039 Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 15 May 2025 01:07:40 -0400
Subject: [PATCH 04/44] CI: Use public ARM64 Github actions runners for ARM64
builds.
Currently, Invidious uses QEMU to build it's ARM64 Invidious image,
which is slow (since we are basically using a virtual machine).
This helps with the speed of building ARM64 binaries for Invidious
on each release/commit.
More information about the public ARM64 runners here:
https://github.com/orgs/community/discussions/148648
CI: Use ARM64 compose file for build-docker-arm64
---
.github/workflows/build-nightly-container.yml | 55 +++++++------------
.github/workflows/build-stable-container.yml | 55 +++++++------------
.github/workflows/ci.yml | 20 ++-----
docker-compose-arm64.yml | 55 +++++++++++++++++++
4 files changed, 101 insertions(+), 84 deletions(-)
create mode 100644 docker-compose-arm64.yml
diff --git a/.github/workflows/build-nightly-container.yml b/.github/workflows/build-nightly-container.yml
index 4149bd0b..3277c015 100644
--- a/.github/workflows/build-nightly-container.yml
+++ b/.github/workflows/build-nightly-container.yml
@@ -17,17 +17,27 @@ on:
jobs:
release:
- runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ include:
+ - os: ubuntu-latest
+ platforms: linux/amd64
+ name: "AMD64"
+ dockerfile: "docker/Dockerfile"
+ tag_suffix: ""
+ # GitHub doesn't has a ubuntu-latest-arm runner
+ - os: ubuntu-24.04-arm
+ platforms: linux/arm64/v8
+ name: "ARM64"
+ dockerfile: "docker/Dockerfile.arm64"
+ tag_suffix: "-arm64"
+
+ runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v3
- with:
- platforms: arm64
-
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
@@ -43,45 +53,22 @@ jobs:
uses: docker/metadata-action@v5
with:
images: quay.io/invidious/invidious
+ flavor: |
+ suffix=${{ matrix.tag_suffix }}
tags: |
type=sha,format=short,prefix={{date 'YYYY.MM.DD'}}-,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
type=raw,value=master,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
labels: |
quay.expires-after=12w
- - name: Build and push Docker AMD64 image for Push Event
+ - name: Build and push Docker ${{ matrix.name }} image for Push Event
uses: docker/build-push-action@v6
with:
context: .
- file: docker/Dockerfile
- platforms: linux/amd64
+ file: ${{ matrix.dockerfile }}
+ platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
push: true
tags: ${{ steps.meta.outputs.tags }}
build-args: |
"release=1"
-
- - name: Docker meta
- id: meta-arm64
- uses: docker/metadata-action@v5
- with:
- images: quay.io/invidious/invidious
- flavor: |
- suffix=-arm64
- tags: |
- type=sha,format=short,prefix={{date 'YYYY.MM.DD'}}-,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
- type=raw,value=master,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
- labels: |
- quay.expires-after=12w
-
- - name: Build and push Docker ARM64 image for Push Event
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/Dockerfile.arm64
- platforms: linux/arm64/v8
- labels: ${{ steps.meta-arm64.outputs.labels }}
- push: true
- tags: ${{ steps.meta-arm64.outputs.tags }}
- build-args: |
- "release=1"
diff --git a/.github/workflows/build-stable-container.yml b/.github/workflows/build-stable-container.yml
index 1a23e68c..1498dc2e 100644
--- a/.github/workflows/build-stable-container.yml
+++ b/.github/workflows/build-stable-container.yml
@@ -8,17 +8,27 @@ on:
jobs:
release:
- runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ include:
+ - os: ubuntu-latest
+ platforms: linux/amd64
+ name: "AMD64"
+ dockerfile: "docker/Dockerfile"
+ tag_suffix: ""
+ # GitHub doesn't has a ubuntu-latest-arm runner
+ - os: ubuntu-24.04-arm
+ platforms: linux/arm64/v8
+ name: "ARM64"
+ dockerfile: "docker/Dockerfile.arm64"
+ tag_suffix: "-arm64"
+
+ runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v3
- with:
- platforms: arm64
-
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
@@ -36,46 +46,21 @@ jobs:
images: quay.io/invidious/invidious
flavor: |
latest=false
+ suffix=${{ matrix.tag_suffix }}
tags: |
type=semver,pattern={{version}}
type=raw,value=latest
labels: |
quay.expires-after=12w
- - name: Build and push Docker AMD64 image for Push Event
+ - name: Build and push Docker ${{ matrix.name }} image for Push Event
uses: docker/build-push-action@v6
with:
context: .
- file: docker/Dockerfile
- platforms: linux/amd64
+ file: ${{ matrix.dockerfile }}
+ platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
push: true
tags: ${{ steps.meta.outputs.tags }}
build-args: |
"release=1"
-
- - name: Docker meta
- id: meta-arm64
- uses: docker/metadata-action@v5
- with:
- images: quay.io/invidious/invidious
- flavor: |
- latest=false
- suffix=-arm64
- tags: |
- type=semver,pattern={{version}}
- type=raw,value=latest
- labels: |
- quay.expires-after=12w
-
- - name: Build and push Docker ARM64 image for Push Event
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/Dockerfile.arm64
- platforms: linux/arm64/v8
- labels: ${{ steps.meta-arm64.outputs.labels }}
- push: true
- tags: ${{ steps.meta-arm64.outputs.tags }}
- build-args: |
- "release=1"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9d6a930a..c8805d10 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -100,26 +100,16 @@ jobs:
build-docker-arm64:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v3
- with:
- platforms: arm64
+ - name: Build Docker
+ run: docker compose -f docker-compose-arm64.yml build --build-arg release=0
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
-
- - name: Build Docker ARM64 image
- uses: docker/build-push-action@v6
- with:
- context: .
- file: docker/Dockerfile.arm64
- platforms: linux/arm64/v8
- build-args: release=0
+ - name: Run Docker
+ run: docker compose -f docker-compose-arm64.yml up -d
- name: Test Docker
run: while curl -Isf http://localhost:3000; do sleep 1; done
diff --git a/docker-compose-arm64.yml b/docker-compose-arm64.yml
new file mode 100644
index 00000000..ba9e0a3f
--- /dev/null
+++ b/docker-compose-arm64.yml
@@ -0,0 +1,55 @@
+# Warning: This docker-compose file is made for development purposes.
+# Using it will build an image from the locally cloned repository.
+#
+# If you want to use Invidious in production, see the docker-compose.yml file provided
+# in the installation documentation: https://docs.invidious.io/installation/
+
+version: "3"
+services:
+
+ invidious:
+ build:
+ context: .
+ dockerfile: docker/Dockerfile.arm64
+ restart: unless-stopped
+ ports:
+ - "127.0.0.1:3000:3000"
+ environment:
+ # Please read the following file for a comprehensive list of all available
+ # configuration options and their associated syntax:
+ # https://github.com/iv-org/invidious/blob/master/config/config.example.yml
+ INVIDIOUS_CONFIG: |
+ db:
+ dbname: invidious
+ user: kemal
+ password: kemal
+ host: invidious-db
+ port: 5432
+ check_tables: true
+ # external_port:
+ # domain:
+ # https_only: false
+ # statistics_enabled: false
+ hmac_key: "CHANGE_ME!!"
+ healthcheck:
+ test: wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/trending || exit 1
+ interval: 30s
+ timeout: 5s
+ retries: 2
+
+ invidious-db:
+ image: docker.io/library/postgres:14
+ restart: unless-stopped
+ volumes:
+ - postgresdata:/var/lib/postgresql/data
+ - ./config/sql:/config/sql
+ - ./docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh
+ environment:
+ POSTGRES_DB: invidious
+ POSTGRES_USER: kemal
+ POSTGRES_PASSWORD: kemal
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
+
+volumes:
+ postgresdata:
From cef0097a309847f6075d7e9173c0362dcc83c757 Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 15 May 2025 15:28:14 -0400
Subject: [PATCH 05/44] CI: fix typo on matrix platforms
---
.github/workflows/build-nightly-container.yml | 4 ++--
.github/workflows/build-stable-container.yml | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/build-nightly-container.yml b/.github/workflows/build-nightly-container.yml
index 3277c015..6b9d4a87 100644
--- a/.github/workflows/build-nightly-container.yml
+++ b/.github/workflows/build-nightly-container.yml
@@ -21,13 +21,13 @@ jobs:
matrix:
include:
- os: ubuntu-latest
- platforms: linux/amd64
+ platform: linux/amd64
name: "AMD64"
dockerfile: "docker/Dockerfile"
tag_suffix: ""
# GitHub doesn't has a ubuntu-latest-arm runner
- os: ubuntu-24.04-arm
- platforms: linux/arm64/v8
+ platform: linux/arm64/v8
name: "ARM64"
dockerfile: "docker/Dockerfile.arm64"
tag_suffix: "-arm64"
diff --git a/.github/workflows/build-stable-container.yml b/.github/workflows/build-stable-container.yml
index 1498dc2e..07a3520b 100644
--- a/.github/workflows/build-stable-container.yml
+++ b/.github/workflows/build-stable-container.yml
@@ -12,13 +12,13 @@ jobs:
matrix:
include:
- os: ubuntu-latest
- platforms: linux/amd64
+ platform: linux/amd64
name: "AMD64"
dockerfile: "docker/Dockerfile"
tag_suffix: ""
# GitHub doesn't has a ubuntu-latest-arm runner
- os: ubuntu-24.04-arm
- platforms: linux/arm64/v8
+ platform: linux/arm64/v8
name: "ARM64"
dockerfile: "docker/Dockerfile.arm64"
tag_suffix: "-arm64"
From 1d2f4b68133231c66e18d878706e8e263e47a66f Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 15 May 2025 15:29:24 -0400
Subject: [PATCH 06/44] CI: fix typo on comment about the os used on the ARM64
builder
---
.github/workflows/build-nightly-container.yml | 2 +-
.github/workflows/build-stable-container.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/build-nightly-container.yml b/.github/workflows/build-nightly-container.yml
index 6b9d4a87..1a5abeea 100644
--- a/.github/workflows/build-nightly-container.yml
+++ b/.github/workflows/build-nightly-container.yml
@@ -25,7 +25,7 @@ jobs:
name: "AMD64"
dockerfile: "docker/Dockerfile"
tag_suffix: ""
- # GitHub doesn't has a ubuntu-latest-arm runner
+ # GitHub doesn't have a ubuntu-latest-arm runner
- os: ubuntu-24.04-arm
platform: linux/arm64/v8
name: "ARM64"
diff --git a/.github/workflows/build-stable-container.yml b/.github/workflows/build-stable-container.yml
index 07a3520b..7c2a276b 100644
--- a/.github/workflows/build-stable-container.yml
+++ b/.github/workflows/build-stable-container.yml
@@ -16,7 +16,7 @@ jobs:
name: "AMD64"
dockerfile: "docker/Dockerfile"
tag_suffix: ""
- # GitHub doesn't has a ubuntu-latest-arm runner
+ # GitHub doesn't have a ubuntu-latest-arm runner
- os: ubuntu-24.04-arm
platform: linux/arm64/v8
name: "ARM64"
From 94f0a7a9d22e46e58447810fbb0da05508162fad Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 15 May 2025 15:31:17 -0400
Subject: [PATCH 07/44] CI: remove --build-arg
Dockerfile and Dockerfile.arm64 already build Invidious without release mode if
`release` argument is not present.
---
.github/workflows/ci.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c8805d10..1bb92101 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -90,7 +90,7 @@ jobs:
- uses: actions/checkout@v4
- name: Build Docker
- run: docker compose build --build-arg release=0
+ run: docker compose build
- name: Run Docker
run: docker compose up -d
@@ -106,7 +106,7 @@ jobs:
- uses: actions/checkout@v4
- name: Build Docker
- run: docker compose -f docker-compose-arm64.yml build --build-arg release=0
+ run: docker compose -f docker-compose-arm64.yml build
- name: Run Docker
run: docker compose -f docker-compose-arm64.yml up -d
From 1d664c759f17b5455d1ffbbe5e276a35dd4202e9 Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 15 May 2025 16:33:03 -0400
Subject: [PATCH 08/44] CI: Use matrix for `build-docker` on ci.yml
---
.github/workflows/ci.yml | 28 ++++++++++------------------
1 file changed, 10 insertions(+), 18 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1bb92101..51a5052d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -83,14 +83,22 @@ jobs:
run: crystal build --warnings all --error-on-warnings --error-trace src/invidious.cr
build-docker:
+ strategy:
+ matrix:
+ include:
+ - os: ubuntu-latest
+ docker_compose_file: "docker-compose.yml"
+ # GitHub doesn't have a ubuntu-latest-arm runner
+ - os: ubuntu-24.04-arm
+ docker_compose_file: "docker-compose-arm64.yml"
- runs-on: ubuntu-latest
+ runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Build Docker
- run: docker compose build
+ run: docker compose -f ${{ matrix.docker_compose_file }} build
- name: Run Docker
run: docker compose up -d
@@ -98,22 +106,6 @@ jobs:
- name: Test Docker
run: while curl -Isf http://localhost:3000; do sleep 1; done
- build-docker-arm64:
-
- runs-on: ubuntu-24.04-arm
-
- steps:
- - uses: actions/checkout@v4
-
- - name: Build Docker
- run: docker compose -f docker-compose-arm64.yml build
-
- - name: Run Docker
- run: docker compose -f docker-compose-arm64.yml up -d
-
- - name: Test Docker
- run: while curl -Isf http://localhost:3000; do sleep 1; done
-
lint:
runs-on: ubuntu-latest
From a3375e512edf00c5c0c00089d370392c37bbe550 Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 15 May 2025 17:43:03 -0400
Subject: [PATCH 09/44] CI: Add name attribute to `build-docker` job
---
.github/workflows/ci.yml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 51a5052d..80cb81a0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -88,10 +88,13 @@ jobs:
include:
- os: ubuntu-latest
docker_compose_file: "docker-compose.yml"
+ name: "AMD64"
# GitHub doesn't have a ubuntu-latest-arm runner
- os: ubuntu-24.04-arm
docker_compose_file: "docker-compose-arm64.yml"
+ name: "ARM64"
+ name: Test ${{ matrix.name }} Docker build
runs-on: ${{ matrix.os }}
steps:
From 033a44fab574df56dd63a41d63d089b84cdb31f5 Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 15 May 2025 17:58:24 -0400
Subject: [PATCH 10/44] CI: Also use `matrix.docker_compose_file` for `Run
Docker` step
---
.github/workflows/ci.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 80cb81a0..d3b6455a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -104,7 +104,7 @@ jobs:
run: docker compose -f ${{ matrix.docker_compose_file }} build
- name: Run Docker
- run: docker compose up -d
+ run: docker compose -f ${{ matrix.docker_compose_file }} up -d
- name: Test Docker
run: while curl -Isf http://localhost:3000; do sleep 1; done
From 381074fce1f3e405d8c527a672f524c4700aead5 Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 15 May 2025 19:38:21 -0400
Subject: [PATCH 11/44] CI: Replace Dockerfile path depending of the os used
---
.github/workflows/ci.yml | 10 +++++---
docker-compose-arm64.yml | 55 ----------------------------------------
2 files changed, 6 insertions(+), 59 deletions(-)
delete mode 100644 docker-compose-arm64.yml
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d3b6455a..7a5e8850 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -87,11 +87,9 @@ jobs:
matrix:
include:
- os: ubuntu-latest
- docker_compose_file: "docker-compose.yml"
name: "AMD64"
# GitHub doesn't have a ubuntu-latest-arm runner
- os: ubuntu-24.04-arm
- docker_compose_file: "docker-compose-arm64.yml"
name: "ARM64"
name: Test ${{ matrix.name }} Docker build
@@ -100,11 +98,15 @@ jobs:
steps:
- uses: actions/checkout@v4
+ - name: Use ARM64 Dockerfile if ARM64
+ if: ${{ matrix.name }} == "ARM64"
+ run: sed -i 's/Dockerfile/Dockerfile.arm64/' docker-compose.yml
+
- name: Build Docker
- run: docker compose -f ${{ matrix.docker_compose_file }} build
+ run: docker compose build
- name: Run Docker
- run: docker compose -f ${{ matrix.docker_compose_file }} up -d
+ run: docker compose up -d
- name: Test Docker
run: while curl -Isf http://localhost:3000; do sleep 1; done
diff --git a/docker-compose-arm64.yml b/docker-compose-arm64.yml
deleted file mode 100644
index ba9e0a3f..00000000
--- a/docker-compose-arm64.yml
+++ /dev/null
@@ -1,55 +0,0 @@
-# Warning: This docker-compose file is made for development purposes.
-# Using it will build an image from the locally cloned repository.
-#
-# If you want to use Invidious in production, see the docker-compose.yml file provided
-# in the installation documentation: https://docs.invidious.io/installation/
-
-version: "3"
-services:
-
- invidious:
- build:
- context: .
- dockerfile: docker/Dockerfile.arm64
- restart: unless-stopped
- ports:
- - "127.0.0.1:3000:3000"
- environment:
- # Please read the following file for a comprehensive list of all available
- # configuration options and their associated syntax:
- # https://github.com/iv-org/invidious/blob/master/config/config.example.yml
- INVIDIOUS_CONFIG: |
- db:
- dbname: invidious
- user: kemal
- password: kemal
- host: invidious-db
- port: 5432
- check_tables: true
- # external_port:
- # domain:
- # https_only: false
- # statistics_enabled: false
- hmac_key: "CHANGE_ME!!"
- healthcheck:
- test: wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/trending || exit 1
- interval: 30s
- timeout: 5s
- retries: 2
-
- invidious-db:
- image: docker.io/library/postgres:14
- restart: unless-stopped
- volumes:
- - postgresdata:/var/lib/postgresql/data
- - ./config/sql:/config/sql
- - ./docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh
- environment:
- POSTGRES_DB: invidious
- POSTGRES_USER: kemal
- POSTGRES_PASSWORD: kemal
- healthcheck:
- test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
-
-volumes:
- postgresdata:
From cc643f209a95cbf9fcc7e97ae3587454b35c3bc5 Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 15 May 2025 17:49:54 -0400
Subject: [PATCH 12/44] CI: Fix build-docker job not checking if Invidious
starts successfully or not
---
.github/workflows/ci.yml | 12 +++++++++++-
docker-compose.yml | 4 ++++
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7a5e8850..27debc1e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -105,11 +105,21 @@ jobs:
- name: Build Docker
run: docker compose build
+ - name: Change hmac_key on docker-compose.yml
+ run: sed -i '/hmac_key/s/CHANGE_ME!!/docker-build-hmac-key/' docker-compose.yml
+
- name: Run Docker
run: docker compose up -d
- name: Test Docker
- run: while curl -Isf http://localhost:3000; do sleep 1; done
+ id: test
+ run: curl -If http://localhost:3000 --retry 5 --retry-delay 1 --retry-all-errors
+
+ - name: Print Invidious container logs
+ # Tells Github Actions to always run this step regardless of whether the previous step has failed
+ # Without this expression this step would simply be skipped when the previous step fails.
+ if: success() || steps.test.conclusion == 'failure'
+ run: docker compose logs
lint:
diff --git a/docker-compose.yml b/docker-compose.yml
index afda8726..0de51feb 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -14,6 +14,10 @@ services:
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000"
+ depends_on:
+ invidious-db:
+ condition: service_healthy
+ restart: true
environment:
# Please read the following file for a comprehensive list of all available
# configuration options and their associated syntax:
From f9472e4e4b910acb9962159e97b37c4d95f8b804 Mon Sep 17 00:00:00 2001
From: epicsam123 <92618898+epicsam123@users.noreply.github.com>
Date: Mon, 19 May 2025 22:34:59 -0400
Subject: [PATCH 13/44] revert format
---
assets/css/player.css | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/assets/css/player.css b/assets/css/player.css
index 60f3ce73..d95549ac 100644
--- a/assets/css/player.css
+++ b/assets/css/player.css
@@ -71,10 +71,8 @@
padding-top: 2em
}
-.video-js.player-style-youtube .vjs-progress-control .vjs-progress-holder, .video-js.player-style-youtube .vjs-progress-control {
- height: 5px;
- margin-bottom: 10px;
-}
+.video-js.player-style-youtube .vjs-progress-control .vjs-progress-holder, .video-js.player-style-youtube .vjs-progress-control {height: 5px;
+margin-bottom: 10px;}
ul.vjs-menu-content::-webkit-scrollbar {
display: none;
From 6497e1c41888756b0f624df725712bf3b00d49c2 Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 22 May 2025 16:06:13 -0400
Subject: [PATCH 14/44] YtAPI: Bump client versions
---
src/invidious/yt_backend/youtube_api.cr | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/invidious/yt_backend/youtube_api.cr b/src/invidious/yt_backend/youtube_api.cr
index b40092a1..1f21ddf0 100644
--- a/src/invidious/yt_backend/youtube_api.cr
+++ b/src/invidious/yt_backend/youtube_api.cr
@@ -6,10 +6,10 @@ module YoutubeAPI
extend self
# For Android versions, see https://en.wikipedia.org/wiki/Android_version_history
- private ANDROID_APP_VERSION = "19.32.34"
- private ANDROID_VERSION = "12"
+ private ANDROID_APP_VERSION = "19.35.36"
+ private ANDROID_VERSION = "13"
private ANDROID_USER_AGENT = "com.google.android.youtube/#{ANDROID_APP_VERSION} (Linux; U; Android #{ANDROID_VERSION}; US) gzip"
- private ANDROID_SDK_VERSION = 31_i64
+ private ANDROID_SDK_VERSION = 33_i64
private ANDROID_TS_APP_VERSION = "1.9"
private ANDROID_TS_USER_AGENT = "com.google.android.youtube/1.9 (Linux; U; Android 12; US) gzip"
@@ -49,7 +49,7 @@ module YoutubeAPI
ClientType::Web => {
name: "WEB",
name_proto: "1",
- version: "2.20240814.00.00",
+ version: "2.20250222.10.00",
screen: "WATCH_FULL_SCREEN",
os_name: "Windows",
os_version: WINDOWS_VERSION,
@@ -58,7 +58,7 @@ module YoutubeAPI
ClientType::WebEmbeddedPlayer => {
name: "WEB_EMBEDDED_PLAYER",
name_proto: "56",
- version: "1.20240812.01.00",
+ version: "1.20250219.01.00",
screen: "EMBED",
os_name: "Windows",
os_version: WINDOWS_VERSION,
@@ -67,7 +67,7 @@ module YoutubeAPI
ClientType::WebMobile => {
name: "MWEB",
name_proto: "2",
- version: "2.20240813.02.00",
+ version: "2.20250224.01.00",
os_name: "Android",
os_version: ANDROID_VERSION,
platform: "MOBILE",
@@ -75,7 +75,7 @@ module YoutubeAPI
ClientType::WebScreenEmbed => {
name: "WEB",
name_proto: "1",
- version: "2.20240814.00.00",
+ version: "2.20250222.10.00",
screen: "EMBED",
os_name: "Windows",
os_version: WINDOWS_VERSION,
@@ -84,7 +84,7 @@ module YoutubeAPI
ClientType::WebCreator => {
name: "WEB_CREATOR",
name_proto: "62",
- version: "1.20240918.03.00",
+ version: "1.20241203.01.00",
os_name: "Windows",
os_version: WINDOWS_VERSION,
platform: "DESKTOP",
@@ -170,7 +170,7 @@ module YoutubeAPI
ClientType::TvHtml5 => {
name: "TVHTML5",
name_proto: "7",
- version: "7.20240813.07.00",
+ version: "7.20250219.14.00",
},
ClientType::TvHtml5ScreenEmbed => {
name: "TVHTML5_SIMPLY_EMBEDDED_PLAYER",
From 97354adf0fc359d2898f69613d1ab668aaf6931f Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 22 May 2025 17:15:45 -0400
Subject: [PATCH 15/44] Update src/invidious/yt_backend/youtube_api.cr
Co-authored-by: syeopite <70992037+syeopite@users.noreply.github.com>
---
src/invidious/yt_backend/youtube_api.cr | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/invidious/yt_backend/youtube_api.cr b/src/invidious/yt_backend/youtube_api.cr
index 1f21ddf0..bedbb978 100644
--- a/src/invidious/yt_backend/youtube_api.cr
+++ b/src/invidious/yt_backend/youtube_api.cr
@@ -8,7 +8,7 @@ module YoutubeAPI
# For Android versions, see https://en.wikipedia.org/wiki/Android_version_history
private ANDROID_APP_VERSION = "19.35.36"
private ANDROID_VERSION = "13"
- private ANDROID_USER_AGENT = "com.google.android.youtube/#{ANDROID_APP_VERSION} (Linux; U; Android #{ANDROID_VERSION}; US) gzip"
+ private ANDROID_USER_AGENT = "com.google.android.youtube/#{ANDROID_APP_VERSION} (Linux; U; Android #{ANDROID_VERSION}; en_US; SM-S908E Build/TP1A.220624.014) gzip"
private ANDROID_SDK_VERSION = 33_i64
private ANDROID_TS_APP_VERSION = "1.9"
From 3a8d4f333f1ef5b42a4eb0a2e8b5743b646862cb Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 22 May 2025 17:17:01 -0400
Subject: [PATCH 16/44] update IOS_APP_VERSION
---
src/invidious/yt_backend/youtube_api.cr | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/invidious/yt_backend/youtube_api.cr b/src/invidious/yt_backend/youtube_api.cr
index bedbb978..5f89d0e6 100644
--- a/src/invidious/yt_backend/youtube_api.cr
+++ b/src/invidious/yt_backend/youtube_api.cr
@@ -17,7 +17,7 @@ module YoutubeAPI
# For Apple device names, see https://gist.github.com/adamawolf/3048717
# For iOS versions, see https://en.wikipedia.org/wiki/IOS_version_history#Releases,
# then go to the dedicated article of the major version you want.
- private IOS_APP_VERSION = "19.32.8"
+ private IOS_APP_VERSION = "20.11.6"
private IOS_USER_AGENT = "com.google.ios.youtube/#{IOS_APP_VERSION} (iPhone14,5; U; CPU iOS 17_6 like Mac OS X;)"
private IOS_VERSION = "17.6.1.21G93" # Major.Minor.Patch.Build
From 09d342b84d4639026b90beb3f95403f6cf93275a Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 22 May 2025 17:55:46 -0400
Subject: [PATCH 17/44] Update src/invidious/yt_backend/youtube_api.cr
Co-authored-by: syeopite <70992037+syeopite@users.noreply.github.com>
---
src/invidious/yt_backend/youtube_api.cr | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/invidious/yt_backend/youtube_api.cr b/src/invidious/yt_backend/youtube_api.cr
index 5f89d0e6..9f2078c7 100644
--- a/src/invidious/yt_backend/youtube_api.cr
+++ b/src/invidious/yt_backend/youtube_api.cr
@@ -18,8 +18,8 @@ module YoutubeAPI
# For iOS versions, see https://en.wikipedia.org/wiki/IOS_version_history#Releases,
# then go to the dedicated article of the major version you want.
private IOS_APP_VERSION = "20.11.6"
- private IOS_USER_AGENT = "com.google.ios.youtube/#{IOS_APP_VERSION} (iPhone14,5; U; CPU iOS 17_6 like Mac OS X;)"
- private IOS_VERSION = "17.6.1.21G93" # Major.Minor.Patch.Build
+ private IOS_USER_AGENT = "com.google.ios.youtube/#{IOS_APP_VERSION} (iPhone14,5; U; CPU iOS 18_5 like Mac OS X;)"
+ private IOS_VERSION = "18.5.0.22F76" # Major.Minor.Patch.Build
private WINDOWS_VERSION = "10.0"
From b859faebf057b7dde7733cfb68b9a3b77d648133 Mon Sep 17 00:00:00 2001
From: syeopite <70992037+syeopite@users.noreply.github.com>
Date: Wed, 28 May 2025 15:34:49 +0000
Subject: [PATCH 18/44] Remove `@iv-org/developers` from codeowners (#5314)
---
.github/CODEOWNERS | 3 ---
1 file changed, 3 deletions(-)
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 9ca09368..9f17bb40 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,6 +1,3 @@
-# Default and lowest precedence. If none of the below matches, @iv-org/developers would be requested for review.
-* @iv-org/developers
-
docker-compose.yml @unixfox
docker/ @unixfox
kubernetes/ @unixfox
From df8839d1f018644afecb15e144f228d811708f8f Mon Sep 17 00:00:00 2001
From: syeopite <70992037+syeopite@users.noreply.github.com>
Date: Wed, 28 May 2025 20:18:51 +0000
Subject: [PATCH 19/44] Make base-Invidious video info extraction more
resilient (#5312)
Try next fallback client if one raises
Convert `dig` to `dig?`
Optimize companionless stream retrieval
---
src/invidious/videos/parser.cr | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr
index 15bd00b6..feb58440 100644
--- a/src/invidious/videos/parser.cr
+++ b/src/invidious/videos/parser.cr
@@ -82,7 +82,7 @@ def extract_video_info(video_id : String)
"reason" => JSON::Any.new(reason),
}
end
- elsif video_id != player_response.dig("videoDetails", "videoId")
+ elsif video_id != player_response.dig?("videoDetails", "videoId")
# YouTube may return a different video player response than expected.
# See: https://github.com/TeamNewPipe/NewPipe/issues/8713
# Line to be reverted if one day we solve the video not available issue.
@@ -109,21 +109,33 @@ def extract_video_info(video_id : String)
params["reason"] = JSON::Any.new(reason) if reason
if !CONFIG.invidious_companion.present?
- if player_response["streamingData"]? && player_response.dig?("streamingData", "adaptiveFormats", 0, "url").nil?
+ if player_response.dig?("streamingData", "adaptiveFormats", 0, "url").nil?
LOGGER.warn("Missing URLs for adaptive formats, falling back to other YT clients.")
- players_fallback = [YoutubeAPI::ClientType::TvHtml5, YoutubeAPI::ClientType::WebMobile]
+ players_fallback = {YoutubeAPI::ClientType::TvHtml5, YoutubeAPI::ClientType::WebMobile}
+
players_fallback.each do |player_fallback|
client_config.client_type = player_fallback
- player_fallback_response = try_fetch_streaming_data(video_id, client_config)
- if player_fallback_response && player_fallback_response["streamingData"]? &&
- player_fallback_response.dig?("streamingData", "adaptiveFormats", 0, "url")
+
+ next if !(player_fallback_response = try_fetch_streaming_data(video_id, client_config))
+
+ if player_fallback_response.dig?("streamingData", "adaptiveFormats", 0, "url")
streaming_data = player_response["streamingData"].as_h
streaming_data["adaptiveFormats"] = player_fallback_response["streamingData"]["adaptiveFormats"]
player_response["streamingData"] = JSON::Any.new(streaming_data)
break
end
+ rescue InfoException
+ next LOGGER.warn("Failed to fetch streams with #{player_fallback}")
end
end
+
+ # Seems like video page can still render even without playable streams.
+ # its better than nothing.
+ #
+ # # Were we able to find playable video streams?
+ # if player_response.dig?("streamingData", "adaptiveFormats", 0, "url").nil?
+ # # No :(
+ # end
end
{"captions", "playabilityStatus", "playerConfig", "storyboards"}.each do |f|
@@ -154,7 +166,7 @@ def try_fetch_streaming_data(id : String, client_config : YoutubeAPI::ClientConf
playability_status = response["playabilityStatus"]["status"]
LOGGER.debug("try_fetch_streaming_data: [#{id}] Got playabilityStatus == #{playability_status}.")
- if id != response.dig("videoDetails", "videoId")
+ if id != response.dig?("videoDetails", "videoId")
# YouTube may return a different video player response than expected.
# See: https://github.com/TeamNewPipe/NewPipe/issues/8713
raise InfoException.new(
From 4daf1f081828dd9137e58bf7a2cc79872f7afa6f Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 12 Jun 2025 01:24:45 -0400
Subject: [PATCH 20/44] Add `TvSimply` client
Data taken from: https://github.com/LuanRT/YouTube.js/commit/8cf658151fc4e4266fadfb7e53dd5db3db693355, https://github.com/LuanRT/YouTube.js/commit/689fb0b90edab6f0e4326a35144541d68f72fe01 and https://github.com/LuanRT/YouTube.js/commit/b15f623dab3acb44eaef33175df2d22d35be2979
---
src/invidious/yt_backend/youtube_api.cr | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/invidious/yt_backend/youtube_api.cr b/src/invidious/yt_backend/youtube_api.cr
index b40092a1..78915aef 100644
--- a/src/invidious/yt_backend/youtube_api.cr
+++ b/src/invidious/yt_backend/youtube_api.cr
@@ -42,6 +42,7 @@ module YoutubeAPI
TvHtml5
TvHtml5ScreenEmbed
+ TvSimply
end
# List of hard-coded values used by the different clients
@@ -178,6 +179,11 @@ module YoutubeAPI
version: "2.0",
screen: "EMBED",
},
+ ClientType::TvSimply => {
+ name: "TVHTML5_SIMPLY",
+ name_proto: "74",
+ version: "1.0",
+ },
}
####################################################################
From 37be513e142061067604d7ec1981fe7a309f8713 Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 12 Jun 2025 01:25:59 -0400
Subject: [PATCH 21/44] Add fallback to TvSimply client
---
src/invidious/videos/parser.cr | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr
index feb58440..5be59352 100644
--- a/src/invidious/videos/parser.cr
+++ b/src/invidious/videos/parser.cr
@@ -111,7 +111,7 @@ def extract_video_info(video_id : String)
if !CONFIG.invidious_companion.present?
if player_response.dig?("streamingData", "adaptiveFormats", 0, "url").nil?
LOGGER.warn("Missing URLs for adaptive formats, falling back to other YT clients.")
- players_fallback = {YoutubeAPI::ClientType::TvHtml5, YoutubeAPI::ClientType::WebMobile}
+ players_fallback = {YoutubeAPI::ClientType::TvHtml5, YoutubeAPI::ClientType::TvSimply, YoutubeAPI::ClientType::WebMobile}
players_fallback.each do |player_fallback|
client_config.client_type = player_fallback
From 0c96e0977fd805731d8fdbe97afac1ee22b6626a Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 12 Jun 2025 16:06:04 -0400
Subject: [PATCH 22/44] check for signatureCipher too
---
src/invidious/videos/parser.cr | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr
index 5be59352..212b3b35 100644
--- a/src/invidious/videos/parser.cr
+++ b/src/invidious/videos/parser.cr
@@ -118,7 +118,7 @@ def extract_video_info(video_id : String)
next if !(player_fallback_response = try_fetch_streaming_data(video_id, client_config))
- if player_fallback_response.dig?("streamingData", "adaptiveFormats", 0, "url")
+ if player_fallback_response.dig?("streamingData", "adaptiveFormats", 0, "url") || player_fallback_response.dig?("streamingData", "adaptiveFormats", 0, "signatureCipher")
streaming_data = player_response["streamingData"].as_h
streaming_data["adaptiveFormats"] = player_fallback_response["streamingData"]["adaptiveFormats"]
player_response["streamingData"] = JSON::Any.new(streaming_data)
From b1e7e0c45e8cfe0ca262dc5774c8ccca3fc6db66 Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 12 Jun 2025 16:18:01 -0400
Subject: [PATCH 23/44] replace url by signatureCipher if url is not present
---
src/invidious/videos/parser.cr | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr
index 212b3b35..e58c0e8f 100644
--- a/src/invidious/videos/parser.cr
+++ b/src/invidious/videos/parser.cr
@@ -146,6 +146,9 @@ def extract_video_info(video_id : String)
if streaming_data = player_response["streamingData"]?
%w[formats adaptiveFormats].each do |key|
streaming_data.as_h[key]?.try &.as_a.each do |format|
+ if format.as_h["url"].nil?
+ format.as_h["url"] = format.as_h["signatureCipher"]
+ end
format.as_h["url"] = JSON::Any.new(convert_url(format))
end
end
From 01cdb384e0629ade15a83f8a2bcb50722d03340c Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 12 Jun 2025 17:25:19 -0400
Subject: [PATCH 24/44] add suggestions from syeopite
---
src/invidious/videos/parser.cr | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr
index e58c0e8f..6892b37c 100644
--- a/src/invidious/videos/parser.cr
+++ b/src/invidious/videos/parser.cr
@@ -146,10 +146,11 @@ def extract_video_info(video_id : String)
if streaming_data = player_response["streamingData"]?
%w[formats adaptiveFormats].each do |key|
streaming_data.as_h[key]?.try &.as_a.each do |format|
- if format.as_h["url"].nil?
- format.as_h["url"] = format.as_h["signatureCipher"]
+ format = format.as_h
+ if format["url"]?.nil?
+ format["url"] = format["signatureCipher"]
end
- format.as_h["url"] = JSON::Any.new(convert_url(format))
+ format["url"] = JSON::Any.new(convert_url(format))
end
end
From 8cd9d53fb1ff4a8a15d208f587a0a4ce330890bd Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Thu, 12 Jun 2025 18:44:01 -0400
Subject: [PATCH 25/44] show message when connection to the database is not
possible
---
src/invidious.cr | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/invidious.cr b/src/invidious.cr
index 69f8a26c..d1f84f39 100644
--- a/src/invidious.cr
+++ b/src/invidious.cr
@@ -60,7 +60,13 @@ alias IV = Invidious
CONFIG = Config.load
HMAC_KEY = CONFIG.hmac_key
-PG_DB = DB.open CONFIG.database_url
+PG_DB = begin
+ DB.open CONFIG.database_url
+rescue ex
+ puts "Failed to connect to PostgreSQL database: #{ex.cause.try &.message}"
+ puts "Check your 'config.yml' database settings or PostgreSQL settings."
+ exit(1)
+end
ARCHIVE_URL = URI.parse("https://archive.org")
PUBSUB_URL = URI.parse("https://pubsubhubbub.appspot.com")
REDDIT_URL = URI.parse("https://www.reddit.com")
From cf0a68bd77251528713404822a19c411a1c0aaca Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Sun, 15 Jun 2025 16:51:04 -0400
Subject: [PATCH 26/44] store adaptiveFormats data into a variable
---
src/invidious/videos/parser.cr | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr
index 6892b37c..178b905b 100644
--- a/src/invidious/videos/parser.cr
+++ b/src/invidious/videos/parser.cr
@@ -118,9 +118,10 @@ def extract_video_info(video_id : String)
next if !(player_fallback_response = try_fetch_streaming_data(video_id, client_config))
- if player_fallback_response.dig?("streamingData", "adaptiveFormats", 0, "url") || player_fallback_response.dig?("streamingData", "adaptiveFormats", 0, "signatureCipher")
+ adaptive_formats = player_fallback_response.dig?("streamingData", "adaptiveFormats")
+ if adaptive_formats && (adaptive_formats.dig?(0, "url") || adaptive_formats.dig?(0, "signatureCipher"))
streaming_data = player_response["streamingData"].as_h
- streaming_data["adaptiveFormats"] = player_fallback_response["streamingData"]["adaptiveFormats"]
+ streaming_data["adaptiveFormats"] = adaptive_formats
player_response["streamingData"] = JSON::Any.new(streaming_data)
break
end
From d51e1cb0514fe2be4b94f7233e36a8aada542496 Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Sun, 15 Jun 2025 17:45:53 -0400
Subject: [PATCH 27/44] remove fallback to TV client
---
src/invidious/videos/parser.cr | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr
index 178b905b..5335aa79 100644
--- a/src/invidious/videos/parser.cr
+++ b/src/invidious/videos/parser.cr
@@ -111,7 +111,7 @@ def extract_video_info(video_id : String)
if !CONFIG.invidious_companion.present?
if player_response.dig?("streamingData", "adaptiveFormats", 0, "url").nil?
LOGGER.warn("Missing URLs for adaptive formats, falling back to other YT clients.")
- players_fallback = {YoutubeAPI::ClientType::TvHtml5, YoutubeAPI::ClientType::TvSimply, YoutubeAPI::ClientType::WebMobile}
+ players_fallback = {YoutubeAPI::ClientType::TvSimply, YoutubeAPI::ClientType::WebMobile}
players_fallback.each do |player_fallback|
client_config.client_type = player_fallback
From 8723fdca06510a2ab64c194fa284f011fd327e42 Mon Sep 17 00:00:00 2001
From: Fijxu
Date: Sat, 21 Jun 2025 12:02:32 -0400
Subject: [PATCH 28/44] Update src/invidious.cr
Co-authored-by: Samantaz Fox
---
src/invidious.cr | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/invidious.cr b/src/invidious.cr
index d1f84f39..2d244dd2 100644
--- a/src/invidious.cr
+++ b/src/invidious.cr
@@ -62,8 +62,8 @@ HMAC_KEY = CONFIG.hmac_key
PG_DB = begin
DB.open CONFIG.database_url
-rescue ex
- puts "Failed to connect to PostgreSQL database: #{ex.cause.try &.message}"
+rescue exc
+ puts "Failed to connect to PostgreSQL database: #{exc.cause.try &.message}"
puts "Check your 'config.yml' database settings or PostgreSQL settings."
exit(1)
end
From f3f6937ffcc703f11173653dc250c7f5bac5d736 Mon Sep 17 00:00:00 2001
From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com>
Date: Wed, 25 Jun 2025 22:22:30 -0400
Subject: [PATCH 29/44] Fix community tab not loading
---
src/invidious/channels/community.cr | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/invidious/channels/community.cr b/src/invidious/channels/community.cr
index 49ffd990..6a296009 100644
--- a/src/invidious/channels/community.cr
+++ b/src/invidious/channels/community.cr
@@ -3,8 +3,8 @@ private IMAGE_QUALITIES = {320, 560, 640, 1280, 2000}
# TODO: Add "sort_by"
def fetch_channel_community(ucid, cursor, locale, format, thin_mode)
if cursor.nil?
- # Egljb21tdW5pdHk%3D is the protobuf object to load "community"
- initial_data = YoutubeAPI.browse(ucid, params: "Egljb21tdW5pdHk%3D")
+ # EgVwb3N0c_IGBAoCSgA%3D is the protobuf object to load "community"
+ initial_data = YoutubeAPI.browse(ucid, params: "EgVwb3N0c_IGBAoCSgA%3D")
items = [] of JSON::Any
extract_items(initial_data) do |item|
From b9171d9dab7e6791376c4cc899ed3b6fa16e5f19 Mon Sep 17 00:00:00 2001
From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com>
Date: Wed, 25 Jun 2025 22:34:26 -0400
Subject: [PATCH 30/44] Update protobuf for individual community post
---
src/invidious/channels/community.cr | 17 +++++++----------
1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/src/invidious/channels/community.cr b/src/invidious/channels/community.cr
index 6a296009..c0688416 100644
--- a/src/invidious/channels/community.cr
+++ b/src/invidious/channels/community.cr
@@ -3,7 +3,7 @@ private IMAGE_QUALITIES = {320, 560, 640, 1280, 2000}
# TODO: Add "sort_by"
def fetch_channel_community(ucid, cursor, locale, format, thin_mode)
if cursor.nil?
- # EgVwb3N0c_IGBAoCSgA%3D is the protobuf object to load "community"
+ # EgVwb3N0c_IGBAoCSgA%3D is the protobuf object to load "posts"
initial_data = YoutubeAPI.browse(ucid, params: "EgVwb3N0c_IGBAoCSgA%3D")
items = [] of JSON::Any
@@ -26,21 +26,18 @@ end
def fetch_channel_community_post(ucid, post_id, locale, format, thin_mode)
object = {
- "2:string" => "community",
- "25:embedded" => {
- "22:string" => post_id.to_s,
- },
- "45:embedded" => {
- "2:varint" => 1_i64,
- "3:varint" => 1_i64,
- },
+ "56:embedded" => {
+ "2:string" => ucid,
+ "3:string" => post_id.to_s,
+ "11:string" => ucid,
+ }
}
params = object.try { |i| Protodec::Any.cast_json(i) }
.try { |i| Protodec::Any.from_json(i) }
.try { |i| Base64.urlsafe_encode(i) }
.try { |i| URI.encode_www_form(i) }
- initial_data = YoutubeAPI.browse(ucid, params: params)
+ initial_data = YoutubeAPI.browse("FEpost_detail", params: params)
items = [] of JSON::Any
extract_items(initial_data) do |item|
From 4155f15bf73ede39434e7aa3878e295d5d203c04 Mon Sep 17 00:00:00 2001
From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com>
Date: Wed, 25 Jun 2025 23:33:28 -0400
Subject: [PATCH 31/44] update resolve_url api to better support new post
endpoint
---
src/invidious/routes/api/v1/misc.cr | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/src/invidious/routes/api/v1/misc.cr b/src/invidious/routes/api/v1/misc.cr
index 4f5b58da..40f2a439 100644
--- a/src/invidious/routes/api/v1/misc.cr
+++ b/src/invidious/routes/api/v1/misc.cr
@@ -190,15 +190,30 @@ module Invidious::Routes::API::V1::Misc
sub_endpoint = endpoint["watchEndpoint"]? || endpoint["browseEndpoint"]? || endpoint
params = sub_endpoint.try &.dig?("params")
+
+ if sub_endpoint["browseId"]?.try &.as_s == "FEpost_detail"
+ decoded_protobuf = params.try &.as_s.try { |i| URI.decode_www_form(i) }
+ .try { |i| Base64.decode(i) }
+ .try { |i| IO::Memory.new(i) }
+ .try { |i| Protodec::Any.parse(i) }
+
+ ucid = decoded_protobuf.try(&.["56:0:embedded"]["2:0:string"].as_s)
+ post_id = decoded_protobuf.try(&.["56:0:embedded"]["3:1:string"].as_s)
+ else
+ ucid = sub_endpoint["browseId"]? if sub_endpoint["browseId"]? && sub_endpoint["browseId"]?.try &.as_s.starts_with? "UC"
+ post_id = nil
+ end
rescue ex
return error_json(500, ex)
end
JSON.build do |json|
json.object do
- json.field "ucid", sub_endpoint["browseId"].as_s if sub_endpoint["browseId"]?
+ json.field "browseId", sub_endpoint["browseId"].as_s if sub_endpoint["browseId"]?
+ json.field "ucid", ucid if ucid != nil
json.field "videoId", sub_endpoint["videoId"].as_s if sub_endpoint["videoId"]?
json.field "playlistId", sub_endpoint["playlistId"].as_s if sub_endpoint["playlistId"]?
json.field "startTimeSeconds", sub_endpoint["startTimeSeconds"].as_i if sub_endpoint["startTimeSeconds"]?
+ json.field "postId", post_id if post_id != nil
json.field "params", params.try &.as_s
json.field "pageType", page_type
end
From 436f955e0f20c9e398e3587175f3071dcec153d4 Mon Sep 17 00:00:00 2001
From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com>
Date: Wed, 25 Jun 2025 23:34:30 -0400
Subject: [PATCH 32/44] update fetch_community_post_comments protobuf to match
currently used protobuf, add sort_by option
---
src/invidious/channels/community.cr | 9 +++++++++
src/invidious/comments/youtube.cr | 26 ++++++++++++++-----------
src/invidious/routes/api/v1/channels.cr | 6 ++++--
src/invidious/routes/channels.cr | 2 +-
4 files changed, 29 insertions(+), 14 deletions(-)
diff --git a/src/invidious/channels/community.cr b/src/invidious/channels/community.cr
index c0688416..8927c81b 100644
--- a/src/invidious/channels/community.cr
+++ b/src/invidious/channels/community.cr
@@ -24,6 +24,15 @@ def fetch_channel_community(ucid, cursor, locale, format, thin_mode)
return extract_channel_community(items, ucid: ucid, locale: locale, format: format, thin_mode: thin_mode)
end
+def decode_ucid_from_post_protobuf(params)
+ decoded_protobuf = params.try { |i| URI.decode_www_form(i) }
+ .try { |i| Base64.decode(i) }
+ .try { |i| IO::Memory.new(i) }
+ .try { |i| Protodec::Any.parse(i) }
+
+ return decoded_protobuf.try(&.["56:0:embedded"]["2:0:string"].as_s)
+end
+
def fetch_channel_community_post(ucid, post_id, locale, format, thin_mode)
object = {
"56:embedded" => {
diff --git a/src/invidious/comments/youtube.cr b/src/invidious/comments/youtube.cr
index 0716fcde..18403656 100644
--- a/src/invidious/comments/youtube.cr
+++ b/src/invidious/comments/youtube.cr
@@ -16,34 +16,38 @@ module Invidious::Comments
return parse_youtube(id, response, format, locale, thin_mode, sort_by)
end
- def fetch_community_post_comments(ucid, post_id)
+ def fetch_community_post_comments(ucid, post_id, sort_by = "top")
object = {
- "2:string" => "community",
- "25:embedded" => {
- "22:string" => post_id,
- },
- "45:embedded" => {
- "2:varint" => 1_i64,
- "3:varint" => 1_i64,
- },
+ "2:string" => "posts",
"53:embedded" => {
"4:embedded" => {
"6:varint" => 0_i64,
- "27:varint" => 1_i64,
+ "15:varint" => 2_i64,
+ "25:varint" => 0_i64,
"29:string" => post_id,
"30:string" => ucid,
},
+ "7:varint" => 0_i64,
"8:string" => "comments-section",
},
}
+ case sort_by
+ when "top"
+ object["53:embedded"].as(Hash)["4:embedded"].as(Hash)["6:varint"] = 0_i64
+ when "new", "newest"
+ object["53:embedded"].as(Hash)["4:embedded"].as(Hash)["6:varint"] = 1_i64
+ else # top
+ object["53:embedded"].as(Hash)["4:embedded"].as(Hash)["6:varint"] = 0_i64
+ end
+
object_parsed = object.try { |i| Protodec::Any.cast_json(i) }
.try { |i| Protodec::Any.from_json(i) }
.try { |i| Base64.urlsafe_encode(i) }
object2 = {
"80226972:embedded" => {
- "2:string" => ucid,
+ "2:string" => "FEcomment_post_detail_page_web_top_level",
"3:string" => object_parsed,
},
}
diff --git a/src/invidious/routes/api/v1/channels.cr b/src/invidious/routes/api/v1/channels.cr
index a940ee68..503b8c05 100644
--- a/src/invidious/routes/api/v1/channels.cr
+++ b/src/invidious/routes/api/v1/channels.cr
@@ -436,7 +436,7 @@ module Invidious::Routes::API::V1::Channels
if ucid.nil?
response = YoutubeAPI.resolve_url("https://www.youtube.com/post/#{id}")
return error_json(400, "Invalid post ID") if response["error"]?
- ucid = response.dig("endpoint", "browseEndpoint", "browseId").as_s
+ ucid = decode_ucid_from_post_protobuf(response.dig("endpoint", "browseEndpoint", "params").as_s)
else
ucid = ucid.to_s
end
@@ -460,13 +460,15 @@ module Invidious::Routes::API::V1::Channels
format = env.params.query["format"]?
format ||= "json"
+ sort_by = env.params.query["sort_by"]?.try &.downcase
+ sort_by ||= "top"
continuation = env.params.query["continuation"]?
case continuation
when nil, ""
ucid = env.params.query["ucid"]
- comments = Comments.fetch_community_post_comments(ucid, id)
+ comments = Comments.fetch_community_post_comments(ucid, id, sort_by: sort_by)
else
comments = YoutubeAPI.browse(continuation: continuation)
end
diff --git a/src/invidious/routes/channels.cr b/src/invidious/routes/channels.cr
index 508aa3e4..6d2b4465 100644
--- a/src/invidious/routes/channels.cr
+++ b/src/invidious/routes/channels.cr
@@ -284,7 +284,7 @@ module Invidious::Routes::Channels
response = YoutubeAPI.resolve_url("https://www.youtube.com/post/#{id}")
return error_template(400, "Invalid post ID") if response["error"]?
- ucid = response.dig("endpoint", "browseEndpoint", "browseId").as_s
+ ucid = decode_ucid_from_post_protobuf(response.dig("endpoint", "browseEndpoint", "params").as_s)
post_response = fetch_channel_community_post(ucid, id, locale, "json", thin_mode)
end
From f8febbe2b2fbc618e96cad027619b1acbc8509f4 Mon Sep 17 00:00:00 2001
From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com>
Date: Wed, 25 Jun 2025 23:53:07 -0400
Subject: [PATCH 33/44] format changes
---
src/invidious/channels/community.cr | 12 ++++++------
src/invidious/routes/api/v1/misc.cr | 4 ++--
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/invidious/channels/community.cr b/src/invidious/channels/community.cr
index 8927c81b..43843b11 100644
--- a/src/invidious/channels/community.cr
+++ b/src/invidious/channels/community.cr
@@ -26,9 +26,9 @@ end
def decode_ucid_from_post_protobuf(params)
decoded_protobuf = params.try { |i| URI.decode_www_form(i) }
- .try { |i| Base64.decode(i) }
- .try { |i| IO::Memory.new(i) }
- .try { |i| Protodec::Any.parse(i) }
+ .try { |i| Base64.decode(i) }
+ .try { |i| IO::Memory.new(i) }
+ .try { |i| Protodec::Any.parse(i) }
return decoded_protobuf.try(&.["56:0:embedded"]["2:0:string"].as_s)
end
@@ -36,10 +36,10 @@ end
def fetch_channel_community_post(ucid, post_id, locale, format, thin_mode)
object = {
"56:embedded" => {
- "2:string" => ucid,
- "3:string" => post_id.to_s,
+ "2:string" => ucid,
+ "3:string" => post_id.to_s,
"11:string" => ucid,
- }
+ },
}
params = object.try { |i| Protodec::Any.cast_json(i) }
.try { |i| Protodec::Any.from_json(i) }
diff --git a/src/invidious/routes/api/v1/misc.cr b/src/invidious/routes/api/v1/misc.cr
index 40f2a439..4ae877a8 100644
--- a/src/invidious/routes/api/v1/misc.cr
+++ b/src/invidious/routes/api/v1/misc.cr
@@ -197,8 +197,8 @@ module Invidious::Routes::API::V1::Misc
.try { |i| IO::Memory.new(i) }
.try { |i| Protodec::Any.parse(i) }
- ucid = decoded_protobuf.try(&.["56:0:embedded"]["2:0:string"].as_s)
- post_id = decoded_protobuf.try(&.["56:0:embedded"]["3:1:string"].as_s)
+ ucid = decoded_protobuf.try(&.["56:0:embedded"]["2:0:string"].as_s)
+ post_id = decoded_protobuf.try(&.["56:0:embedded"]["3:1:string"].as_s)
else
ucid = sub_endpoint["browseId"]? if sub_endpoint["browseId"]? && sub_endpoint["browseId"]?.try &.as_s.starts_with? "UC"
post_id = nil
From b0c9f87fbea9a527b1e96774de97dc366e76df12 Mon Sep 17 00:00:00 2001
From: Samantaz Fox
Date: Thu, 26 Jun 2025 19:09:52 +0000
Subject: [PATCH 34/44] Fix missing .id to retrieve first playlist video ID
This was missed in the review of PR 5196
---
src/invidious/routes/embed.cr | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/invidious/routes/embed.cr b/src/invidious/routes/embed.cr
index 930e4915..721a57f8 100644
--- a/src/invidious/routes/embed.cr
+++ b/src/invidious/routes/embed.cr
@@ -20,7 +20,7 @@ module Invidious::Routes::Embed
return error_template(500, ex)
end
- url = "/embed/#{first_playlist_video}?#{env.params.query}"
+ url = "/embed/#{first_playlist_video.id}?#{env.params.query}"
if env.params.query.size > 0
url += "?#{env.params.query}"
From 64ac3b5203a94291bad709ffcaae665e50544485 Mon Sep 17 00:00:00 2001
From: epicsam123 <92618898+epicsam123@users.noreply.github.com>
Date: Thu, 26 Jun 2025 18:40:06 -0400
Subject: [PATCH 35/44] add missing noreferrers
---
assets/js/player.js | 4 ++--
assets/js/watch.js | 2 +-
src/invidious/frontend/watch_page.cr | 2 +-
src/invidious/views/user/data_control.ecr | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/assets/js/player.js b/assets/js/player.js
index f32c9b56..1a20c932 100644
--- a/assets/js/player.js
+++ b/assets/js/player.js
@@ -180,7 +180,7 @@ var shareOptions = {
};
if (location.pathname.startsWith('/embed/')) {
- var overlay_content = '';
+ var overlay_content = '';
player.overlay({
overlays: [
{ start: 'loadstart', content: overlay_content, end: 'playing', align: 'top'},
@@ -450,7 +450,7 @@ if (!video_data.params.listen && video_data.params.annotations) {
if (target === 'current') {
location.href = path;
} else if (target === 'new') {
- open(path, '_blank');
+ open(path, '_blank', 'noopener,noreferrer')
}
});
diff --git a/assets/js/watch.js b/assets/js/watch.js
index d869d40d..ee9c29e8 100644
--- a/assets/js/watch.js
+++ b/assets/js/watch.js
@@ -141,7 +141,7 @@ function get_reddit_comments() {
\
\
\
- {redditPermalinkText} \
+ {redditPermalinkText} \
\
\
{contentHtml}
\
diff --git a/src/invidious/frontend/watch_page.cr b/src/invidious/frontend/watch_page.cr
index 15d925e3..c0926164 100644
--- a/src/invidious/frontend/watch_page.cr
+++ b/src/invidious/frontend/watch_page.cr
@@ -34,7 +34,7 @@ module Invidious::Frontend::WatchPage
str << " class=\"pure-form pure-form-stacked\""
str << " action='#{url}'"
str << " method='post'"
- str << " rel='noopener'"
+ str << " rel='noopener noreferrer'"
str << " target='_blank'>"
str << '\n'
diff --git a/src/invidious/views/user/data_control.ecr b/src/invidious/views/user/data_control.ecr
index 9ce42c99..e57926f5 100644
--- a/src/invidious/views/user/data_control.ecr
+++ b/src/invidious/views/user/data_control.ecr
@@ -14,7 +14,7 @@
From 803311713d43860bcdbba81008544ef2d67bc657 Mon Sep 17 00:00:00 2001
From: ChunkyProgrammer <78101139+ChunkyProgrammer@users.noreply.github.com>
Date: Thu, 26 Jun 2025 15:34:45 -0400
Subject: [PATCH 36/44] make `sort_by` code more legible
---
src/invidious/comments/youtube.cr | 40 +++++++++++++++----------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/src/invidious/comments/youtube.cr b/src/invidious/comments/youtube.cr
index 18403656..e923b2f8 100644
--- a/src/invidious/comments/youtube.cr
+++ b/src/invidious/comments/youtube.cr
@@ -17,11 +17,20 @@ module Invidious::Comments
end
def fetch_community_post_comments(ucid, post_id, sort_by = "top")
+ case sort_by
+ when "top"
+ sort_by_val = 0_i64
+ when "new", "newest"
+ sort_by_val = 1_i64
+ else # top
+ sort_by_val = 0_i64
+ end
+
object = {
"2:string" => "posts",
"53:embedded" => {
"4:embedded" => {
- "6:varint" => 0_i64,
+ "6:varint" => sort_by_val,
"15:varint" => 2_i64,
"25:varint" => 0_i64,
"29:string" => post_id,
@@ -32,15 +41,6 @@ module Invidious::Comments
},
}
- case sort_by
- when "top"
- object["53:embedded"].as(Hash)["4:embedded"].as(Hash)["6:varint"] = 0_i64
- when "new", "newest"
- object["53:embedded"].as(Hash)["4:embedded"].as(Hash)["6:varint"] = 1_i64
- else # top
- object["53:embedded"].as(Hash)["4:embedded"].as(Hash)["6:varint"] = 0_i64
- end
-
object_parsed = object.try { |i| Protodec::Any.cast_json(i) }
.try { |i| Protodec::Any.from_json(i) }
.try { |i| Base64.urlsafe_encode(i) }
@@ -324,6 +324,15 @@ module Invidious::Comments
end
def produce_continuation(video_id, cursor = "", sort_by = "top")
+ case sort_by
+ when "top"
+ sort_by_val = 0_i64
+ when "new", "newest"
+ sort_by_val = 1_i64
+ else # top
+ sort_by_val = 0_i64
+ end
+
object = {
"2:embedded" => {
"2:string" => video_id,
@@ -344,21 +353,12 @@ module Invidious::Comments
"1:string" => cursor,
"4:embedded" => {
"4:string" => video_id,
- "6:varint" => 0_i64,
+ "6:varint" => sort_by_val,
},
"5:varint" => 20_i64,
},
}
- case sort_by
- when "top"
- object["6:embedded"].as(Hash)["4:embedded"].as(Hash)["6:varint"] = 0_i64
- when "new", "newest"
- object["6:embedded"].as(Hash)["4:embedded"].as(Hash)["6:varint"] = 1_i64
- else # top
- object["6:embedded"].as(Hash)["4:embedded"].as(Hash)["6:varint"] = 0_i64
- end
-
continuation = object.try { |i| Protodec::Any.cast_json(i) }
.try { |i| Protodec::Any.from_json(i) }
.try { |i| Base64.urlsafe_encode(i) }
From 227c041b86c97a5197c673af7efadbaf649f812d Mon Sep 17 00:00:00 2001
From: Nami Sunami
Date: Sat, 28 Jun 2025 11:38:31 +0200
Subject: [PATCH 37/44] fix(config.example.yml): Fix typo (effet -> effect)
---
config/config.example.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/config.example.yml b/config/config.example.yml
index 8d3e6212..e8ab658b 100644
--- a/config/config.example.yml
+++ b/config/config.example.yml
@@ -865,7 +865,7 @@ default_user_preferences:
##
## Default dash video quality.
##
- ## Note: this setting only takes effet if the
+ ## Note: this setting only takes effect if the
## 'quality' parameter is set to "dash".
##
## Accepted values:
From 24252b836ceee3bbcfe98a91963439b1bee44dcc Mon Sep 17 00:00:00 2001
From: epicsam123 <92618898+epicsam123@users.noreply.github.com>
Date: Mon, 30 Jun 2025 22:38:30 -0400
Subject: [PATCH 38/44] add back semicolon
---
assets/js/player.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/assets/js/player.js b/assets/js/player.js
index 1a20c932..7ab3d0e7 100644
--- a/assets/js/player.js
+++ b/assets/js/player.js
@@ -450,7 +450,7 @@ if (!video_data.params.listen && video_data.params.annotations) {
if (target === 'current') {
location.href = path;
} else if (target === 'new') {
- open(path, '_blank', 'noopener,noreferrer')
+ open(path, '_blank', 'noopener,noreferrer');
}
});
From a84bb1d22ed4d59deb50d8ecf72fac1e3a8f3ff4 Mon Sep 17 00:00:00 2001
From: fieryhenry <74794355+fieryhenry@users.noreply.github.com>
Date: Fri, 18 Jul 2025 19:02:50 +0000
Subject: [PATCH 39/44] Fix `TRUE` number of notifications
`update_ticker_count` used to use STORAGE_KEY_STREAM to get the number of notifications which is a boolean value, now it uses STORAGE_KEY_NOTIF_COUNT which is an integer
---
assets/js/notifications.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/assets/js/notifications.js b/assets/js/notifications.js
index 55b7a15c..b8d73a82 100644
--- a/assets/js/notifications.js
+++ b/assets/js/notifications.js
@@ -77,7 +77,7 @@ function create_notification_stream(subscriptions) {
function update_ticker_count() {
var notification_ticker = document.getElementById('notification_ticker');
- const notification_count = helpers.storage.get(STORAGE_KEY_STREAM);
+ const notification_count = helpers.storage.get(STORAGE_KEY_NOTIF_COUNT);
if (notification_count > 0) {
notification_ticker.innerHTML =
'' + notification_count + ' ';
From 3335bc8c388677517e5c4b86eb917fd3fdace2f8 Mon Sep 17 00:00:00 2001
From: fieryhenry <74794355+fieryhenry@users.noreply.github.com>
Date: Fri, 18 Jul 2025 19:07:41 +0000
Subject: [PATCH 40/44] Get a count of 0 if STORAGE_KEY_NOTIF_COUNT is not
present in storage
Not sure if this is necessary as I think it should always be present in storage, but just in case it isn't
---
assets/js/notifications.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/assets/js/notifications.js b/assets/js/notifications.js
index b8d73a82..16d9866d 100644
--- a/assets/js/notifications.js
+++ b/assets/js/notifications.js
@@ -77,7 +77,7 @@ function create_notification_stream(subscriptions) {
function update_ticker_count() {
var notification_ticker = document.getElementById('notification_ticker');
- const notification_count = helpers.storage.get(STORAGE_KEY_NOTIF_COUNT);
+ const notification_count = helpers.storage.get(STORAGE_KEY_NOTIF_COUNT) || 0;
if (notification_count > 0) {
notification_ticker.innerHTML =
'' + notification_count + ' ';
From 1ae0f45b0e5dca696986925a06ef4f4b4f43894b Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 12 Aug 2025 15:06:16 +0200
Subject: [PATCH 41/44] Bump actions/checkout from 4 to 5 (#5415)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)
---
updated-dependencies:
- dependency-name: actions/checkout
dependency-version: '5'
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/build-nightly-container.yml | 2 +-
.github/workflows/build-stable-container.yml | 2 +-
.github/workflows/ci.yml | 8 ++++----
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/build-nightly-container.yml b/.github/workflows/build-nightly-container.yml
index 4149bd0b..2f46997a 100644
--- a/.github/workflows/build-nightly-container.yml
+++ b/.github/workflows/build-nightly-container.yml
@@ -21,7 +21,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
diff --git a/.github/workflows/build-stable-container.yml b/.github/workflows/build-stable-container.yml
index 1a23e68c..74fbd74b 100644
--- a/.github/workflows/build-stable-container.yml
+++ b/.github/workflows/build-stable-container.yml
@@ -12,7 +12,7 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 9d6a930a..7a4a7003 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -48,7 +48,7 @@ jobs:
stable: false
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
with:
submodules: true
@@ -87,7 +87,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Build Docker
run: docker compose build --build-arg release=0
@@ -103,7 +103,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
@@ -131,7 +131,7 @@ jobs:
continue-on-error: true
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v5
with:
submodules: true
From 875d8e7e41b58cce007cd3cc5fa8d615815c593a Mon Sep 17 00:00:00 2001
From: Eugene Pakhomov
Date: Wed, 13 Aug 2025 13:26:48 +0300
Subject: [PATCH 42/44] Persist caption settings
---
assets/js/player.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/assets/js/player.js b/assets/js/player.js
index f32c9b56..cce0b030 100644
--- a/assets/js/player.js
+++ b/assets/js/player.js
@@ -5,6 +5,7 @@ var video_data = JSON.parse(document.getElementById('video_data').textContent);
var options = {
liveui: true,
playbackRates: [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0],
+ persistTextTrackSettings: true,
controlBar: {
children: [
'playToggle',
From dd8086e6d9d4fe79e5645cdc494a22877624cc86 Mon Sep 17 00:00:00 2001
From: Kristian Vos
Date: Wed, 13 Aug 2025 15:43:54 +0200
Subject: [PATCH 43/44] fix: fetching channel playlists returned 500 error
---
src/invidious/channels/playlists.cr | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/invidious/channels/playlists.cr b/src/invidious/channels/playlists.cr
index 9b45d0c8..cba1abd9 100644
--- a/src/invidious/channels/playlists.cr
+++ b/src/invidious/channels/playlists.cr
@@ -6,19 +6,19 @@ def fetch_channel_playlists(ucid, author, continuation, sort_by)
case sort_by
when "last", "last_added"
# Equivalent to "&sort=lad"
- # {"2:string": "playlists", "3:varint": 4, "4:varint": 1, "6:varint": 1}
- "EglwbGF5bGlzdHMYBCABMAE%3D"
+ # {"2:string": "playlists", "3:varint": 4, "4:varint": 1, "6:varint": 1, "110:embedded": {"1:embedded": {"8:string": ""}}}
+ "EglwbGF5bGlzdHMYBCABMAHyBgQKAkIA"
when "oldest", "oldest_created"
# formerly "&sort=da"
# Not available anymore :c or maybe ??
- # {"2:string": "playlists", "3:varint": 2, "4:varint": 1, "6:varint": 1}
- "EglwbGF5bGlzdHMYAiABMAE%3D"
+ # {"2:string": "playlists", "3:varint": 2, "4:varint": 1, "6:varint": 1, "110:embedded": {"1:embedded": {"8:string": ""}}}
+ "EglwbGF5bGlzdHMYAiABMAHyBgQKAkIA"
# {"2:string": "playlists", "3:varint": 1, "4:varint": 1, "6:varint": 1}
# "EglwbGF5bGlzdHMYASABMAE%3D"
when "newest", "newest_created"
# Formerly "&sort=dd"
- # {"2:string": "playlists", "3:varint": 3, "4:varint": 1, "6:varint": 1}
- "EglwbGF5bGlzdHMYAyABMAE%3D"
+ # {"2:string": "playlists", "3:varint": 3, "4:varint": 1, "6:varint": 1, "110:embedded": {"1:embedded": {"8:string": ""}}}
+ "EglwbGF5bGlzdHMYAyABMAHyBgQKAkIA"
end
initial_data = YoutubeAPI.browse(ucid, params: params || "")
From 67f93e55d8e9be4c81a58920c4651d2eb1327fd6 Mon Sep 17 00:00:00 2001
From: syeopite
Date: Sat, 23 Aug 2025 03:35:59 -0700
Subject: [PATCH 44/44] Fix "ex" variable collision in invidious.cr
The exception handling for database connections results in an
`ex` variable which Ameba sees as overshadowing the `ex` used by the
`ex` block arg used to define the HTTP status code 500 handler below.
Although this is a non-issue since the db connection exception handling
will cause Invidious to exit, Ameba's nature as a static checker means
that it isn't aware of this.
The simplest fix without a dirty ameba ignore comment is to rename `ex`
within the Kemal handler block below, since `ex` within a begin rescue
block is a Crystal convention that will also cause Ameba to raise when
not adhered to.
---
src/invidious.cr | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/invidious.cr b/src/invidious.cr
index 2d244dd2..197b150c 100644
--- a/src/invidious.cr
+++ b/src/invidious.cr
@@ -62,8 +62,8 @@ HMAC_KEY = CONFIG.hmac_key
PG_DB = begin
DB.open CONFIG.database_url
-rescue exc
- puts "Failed to connect to PostgreSQL database: #{exc.cause.try &.message}"
+rescue ex
+ puts "Failed to connect to PostgreSQL database: #{ex.cause.try &.message}"
puts "Check your 'config.yml' database settings or PostgreSQL settings."
exit(1)
end
@@ -227,8 +227,8 @@ error 404 do |env|
Invidious::Routes::ErrorRoutes.error_404(env)
end
-error 500 do |env, ex|
- error_template(500, ex)
+error 500 do |env, exception|
+ error_template(500, exception)
end
static_headers do |env|