5940 Commits

Author SHA1 Message Date
NeskireDK
0db4d8e682 CI: publish :latest from the arik branch only
The build job had no branch condition and tagged :latest on every run.
A workflow_dispatch on a work branch would therefore publish that branch
to ghcr.io, and Watchtower would deploy it to production the same night.

With the guard, a dispatch on a work branch runs the test job alone —
crystal spec plus the warning-clean build — on a GitHub runner. That is
how this branch gets type-checked: the compiler needs more memory than
LXC 108 has.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 08:38:34 +02:00
NeskireDK
77eee92465 Add specs for the ArikTube settings store
Covers the parts that are dangerous to get wrong and cheap to test,
which is why the validators and the origin matcher are pure functions:

- override precedence: no row keeps the environment value, a row wins,
  a stored empty list is an override rather than absence;
- decoding: a row that is not JSON, not a list, or holds a malformed
  playlist ID or a CIDR proxy is reported and ignored instead of raised,
  so it can never stop the instance from booting;
- validators: CIDR ranges, a host name where an IP belongs, header auth
  enabled with no trusted proxy, and origins carrying a path, query,
  fragment or credentials;
- origin matching: the near misses, "…ariksen.dk.evil.com",
  "…ariksen.dk@evil.com", the origin hidden in a path or query, another
  scheme, another port, a subdomain;
- the gating of both waivers: header auth off, empty list, no assertion,
  an assertion for somebody else.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 06:43:32 +02:00
NeskireDK
c47d9a93f0 Add an admin settings page for the ArikTube extensions
/admin/settings, linked from the administrator section of the
preferences page and refused to everybody else, edits the settings the
fork added: the playlists behind the Popular and Trending feeds, and the
whole trusted-header block.

- The playlists are picked from the instance's public playlists with a
  tick box each and a number beside it for the position, so no ordering
  has to be typed. A text area takes IDs that are not local playlists.
  Unticking everything restores the stock feed for that feed.
- A playlist that is missing or not public is reported as a warning and
  still saved: the feed skips it the same way, and an admin may be
  listing a playlist they are about to create.
- The trusted-header block is refused whole when anything in it is
  wrong, so a half-applied block can never reach the running config. A
  CIDR range and an empty proxy list with the feature on are the two the
  page exists to catch.
- A save writes the rows and applies the values to the running CONFIG,
  so it needs no restart, and it survives one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 06:43:27 +02:00
NeskireDK
437c6194d6 Auto-approve token consent for SSO sessions on listed origins
A client behind the same authenticating proxy - Materialious behind
Authelia - still had to click through the token consent page, although
the proxy had just authenticated the same person for the same origin.

trusted_header_auth.auto_approve_token_callbacks lists exact origins.
When /authorize_token is reached with a callback on one of them, and the
trusted header asserts the session user on that very request, the token
is issued with the requested scopes and the browser is sent back to the
callback exactly as the consent POST would have sent it.

Every rail is a whole-value check:

- the callback origin is normalized (scheme and host lowercased, default
  port dropped) and compared whole against normalized entries, so
  neither "https://yt.example.com.evil.tld" nor a path can match;
- a URL carrying credentials is refused outright, which is what stops
  "https://yt.example.com@evil.tld";
- a password-login session never qualifies, header auth must be on, and
  an empty list (the default) leaves the consent page exactly as it was.

The redirect URL is now built in one place, shared with the consent POST,
so both hand the client the identical URL.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 06:25:14 +02:00
NeskireDK
fae22d037e Gate the SSO password waiver on password_self_service
The waiver that lets a trusted-header session set a password without the
current one was unconditional. It is the right default — those accounts
were provisioned with a random password nobody ever saw — but an admin
who wants the current password from everybody had no way to say so.

Both call sites now go through TrustedHeaderAuth.password_self_service?,
which folds the flag into the identity check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 06:18:56 +02:00
NeskireDK
c0a6587d52 Store the fork's settings in Postgres, overriding the config
Production feeds the config through INVIDIOUS_CONFIG, so a config.yml
written at runtime is thrown away on the next restart. The fork's own
settings therefore need a home the admin can write to: a key/value table
arik_settings, one row per setting.

- The environment config is parsed and validated first and seeds every
  value; a stored row then overrides the value of its own key. A key
  without a row keeps the environment value.
- Applied at boot right after the table integrity check, so Config.check
  still fails closed on a bad environment config while a bad database
  row only loses its own override: decoding reports the reason and the
  environment value stands.
- Validation lives in ArikSettings and is pure, so the admin UI can
  refuse an entry before it is stored. It refuses what hurts later: a
  CIDR range in trusted_proxies (Config.check exits on it at the next
  boot), header auth enabled with no trusted proxy at all, and callback
  origins that are not a bare scheme+host+port.
- Two new trusted_header_auth fields are declared here and wired up in
  the commits that follow: password_self_service and
  auto_approve_token_callbacks.

The table is created both by a migration and by check_integrity, so
instances on either path get it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 06:14:01 +02:00
NeskireDK
b3272e62a4 Show real view counts in playlist-backed feeds
The playlist tables store no views, so Trending/Popular reported 0 for
every item. The companion suggestion bot already caches YouTube metadata
in suggest.video_meta in the same database: look the counts up in one
query per feed and fall back to 0 when the row or the whole schema is
missing, so instances without the bot are unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 21:21:03 +02:00
NeskireDK
5025d06c00 Allow SSO sessions to set a password without the current one
Accounts provisioned by trusted-header SSO get a random password the user
never saw, so /change_password was unusable for them. When the trusted
header asserts the same email as the session user, waive the current
password check and hide the field, so native clients (Yattee) can be given
a password to log in with.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 21:02:26 +02:00
NeskireDK
c644d73def Add playlist-backed Trending/Popular feeds
New config lists trending_playlists / popular_playlists. When set,
the feed serves the merged content of those local PUBLIC playlists
instead of the stock feed:

- Swap at the data layer (fetch_trending, popular_videos), so the
  HTML views and /api/v1/trending|popular emit the same items and
  API clients (Yattee, Materialious) need no changes.
- Playlists merge in config order, each in its own order,
  duplicates dropped. Missing or non-public entries are skipped
  and logged, never fatal.
- One local Postgres query per playlist — no YouTube call.
- PlaylistVideo converts to SearchVideo with neutral defaults for
  metadata a playlist row lacks (views, description, thumbnails).
- Trending category tabs and region are ignored while set. With a
  single trending playlist, 'View as playlist' links to it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 18:47:52 +02:00
NeskireDK
31fe847126 Fix workflow and submodule configuration
Update mocks submodule to use the upstream iv-org repository
(https://github.com/iv-org/mocks) instead of the inaccessible
NeskireDK fork path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 18:03:02 +02:00
NeskireDK
3fa2f55437 Fix workflow submodule checkout failure
Remove submodules: true from actions/checkout since the mocks
submodule is not accessible and not needed for the build.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 18:00:03 +02:00
NeskireDK
f771983e25 CI: build+push ArikTube container to ghcr.io on the arik branch
Gate first: crystal spec + format-strict build on 1.20.3 (mirrors
upstream ci.yml). Then a linux/amd64 image build pushed as
ghcr.io/neskiredk/invidious:latest + :sha-<commit>. No expiry label.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 17:57:42 +02:00
NeskireDK
8e5a9e079e Add trusted-header authentication (Authelia SSO)
New config block trusted_header_auth. When enabled, before_all
resolves the session from the proxy-asserted header (default
Remote-User) instead of only the SID cookie:

- The header is honored only when the direct TCP peer is in
  trusted_proxies (literal IPs, IPv4-mapped IPv6 normalized).
  X-Forwarded-For is never consulted. Duplicated headers reject.
- /api/ is excluded: token clients (Yattee) are unaffected.
- Unknown users are provisioned like manual registration, with the
  subscriptions materialized view and a random bcrypt password.
  Both statements tolerate concurrent provisioning.
- A session cookie is set and reused; a cookie that belongs to a
  different user is dropped (identity-switch guard).
- Boot fails closed: enabled without valid trusted_proxies exits.
- Optional logout_url replaces the local sign-out form so logout
  ends the proxy session, not just the Invidious one.

The reverse proxy MUST strip the header on routes that bypass its
authentication (see config.example.yml warning).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 17:49:53 +02:00
NeskireDK
cce26864ad ArikTube headline brand: logo + red accent theme
Header/homepage brand text becomes 'ArikTube' with an inline
play-button logo. Everything else keeps the Invidious name --
this fork extends Invidious, it does not rebrand it.
Blue accents (rgb 0,182,240 / #075A9E / #008bec) become a red
scheme (#cc0000 fills, #ff5252 dark-theme text, red seekbar).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 17:46:37 +02:00
github-actions[bot]
48c6110a83
Release v2.20260804.1 (#5896)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
v2.20260804.1
2026-08-04 21:01:38 -04:00
Fijxu
673254e762
fix: pass -no-pie link flag argument to include debug information again for OCI (#5895)
* fix: pass `-no-pie` link flag argument to include debug information again for OCI

* remove space char
2026-08-04 19:11:38 -04:00
Fijxu
df0b02efc0
Prepare for next release 2026-08-04 18:30:20 -04:00
github-actions[bot]
1d1f404b9a
Release v2.20260804.0 (#5893)
* Release v2.20260804.0

* Update CHANGELOG.md

Co-authored-by: TheFrenchGhosty <47571719+TheFrenchGhosty@users.noreply.github.com>

* Update CHANGELOG.md

Co-authored-by: TheFrenchGhosty <47571719+TheFrenchGhosty@users.noreply.github.com>

* Update CHANGELOG.md

Co-authored-by: TheFrenchGhosty <47571719+TheFrenchGhosty@users.noreply.github.com>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Fijxu <fijxu@nadeko.net>
Co-authored-by: TheFrenchGhosty <47571719+TheFrenchGhosty@users.noreply.github.com>
v2.20260804.0
2026-08-04 18:24:23 -04:00
Fijxu
66fb829dbc
CI: Exclude development dependencies from build job (#5860)
* CI: Exclude development dependencies from build job

* use --production and then install spectator to skip building of Ameba

* this should prevent ameba from building
2026-08-03 17:15:31 -04:00
TheFrenchGhosty
4b014bdc82
Enable the Uzbek since it's been translated at more than 20% (#5891) 2026-08-03 23:03:45 +02:00
Weblate (bot)
c1625119a7
Translations update from Hosted Weblate (#5881)
* Update Armenian translation

Update Armenian translation

Update Armenian translation

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Maxim Mkrtchyan <mikurasua@gmail.com>

* Update Polish translation

Co-authored-by: Matthaiks <kitynska@gmail.com>

* Update Uzbek translation

Add Uzbek translation

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Zafarx94 <zfrx94@mail.ru>

---------

Co-authored-by: Maxim Mkrtchyan <mikurasua@gmail.com>
Co-authored-by: Matthaiks <kitynska@gmail.com>
Co-authored-by: Zafarx94 <zfrx94@mail.ru>
2026-08-03 22:56:22 +02:00
TheFrenchGhosty
83882a17b6
Switch to deepseek/deepseek-v4-flash-0731 for the release script (#5886)
* Switch to deepseek/deepseek-v4-flash-0731 for the release script

* Make the change in the workflow file too
2026-08-03 22:55:44 +02:00
dependabot[bot]
0c3d3e8f8a
chore(deps): bump actions/stale from 10 to 11 (#5890)
Bumps [actions/stale](https://github.com/actions/stale) from 10 to 11.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v10...v11)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: '11'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-03 22:55:13 +02:00
Émilien (perso)
1a3cb60282
feat: add support for SOCKS5 proxy (#5865) 2026-08-03 22:43:18 +02:00
Fijxu
cb88a805e5
feat: allow setting videojs max buffer length via config.yml (#5876) 2026-08-03 15:52:50 -04:00
Fijxu
b4b6e992fc
fix: fix rendered links and timestamps in video descriptions (#5878)
* Revert "Fix disappearing end of the comments with emoji (#5587)"

This reverts commit 86c425b43f75dd1f22034bbfbd99476651661348.

* fix: fix rendered links and timestamps in video descriptions
2026-08-03 15:43:50 -04:00
Fijxu
9c70265a9a
fix: add missing HTML.escape call for commit 4501c9d 2026-08-03 15:24:47 -04:00
syeopite
4501c9df9c
Show message when comments are turned off (#4051)
* Add error message when comments are disabled

* Add btn to try reddit comments when yt is disabled

* Escape warning messages for disabled comments

* Add missing semicolons

* Update comment detection to not use msg renderer

* Use short syntax for comment entry-point detection

Co-authored-by: Samantaz Fox <coding@samantaz.fr>

* Condense try-reddit-comments-link HTML in player.js

Co-authored-by: Samantaz Fox <coding@samantaz.fr>

* Improve locale keys for comments disabled messages

Co-authored-by: Samantaz Fox <coding@samantaz.fr>

* Remove extra whitespace

* Use button instead of anchor for try reddit link

* Request Reddit comm when yt disabled during nojs=1

* Change order of commentsEnabled in parse results

* Lint

* Rebase error

* update the naming of the comments section in Innertube

Downstreamed from 36ac67610d

---------

Co-authored-by: Samantaz Fox <coding@samantaz.fr>
Co-authored-by: Fijxu <fijxu@nadeko.net>
2026-08-03 15:18:13 -04:00
TheFrenchGhosty
986471320d
Enable the new locales translated at more than 20% (#5882)
* Enable the new locales translated at more than 20%

* Align all the comments on column 43
2026-08-03 19:34:57 +02:00
Fijxu
47b5d79ec7
fix: also fix comments community posts. (#5874)
Community posts comments still preserve the old author thumbnails
format that has an Array of thumbnails. I forgot to check that as I had
no idea `comments_youtube.cr` was also used for community posts comments

```json
"authorThumbnail": {
    "thumbnails": [
        {
            "url": "//yt3.googleusercontent.com/ytc/AIdro_m9CJFVl3bEWvGnNnN4G9ErBO2lTpKePWCjx_FQtLWaDww=s32-c-k-c0x00ffffff-no-rj-mo",
            "width": 32,
            "height": 32
        },
        {
            "url": "//yt3.googleusercontent.com/ytc/AIdro_m9CJFVl3bEWvGnNnN4G9ErBO2lTpKePWCjx_FQtLWaDww=s48-c-k-c0x00ffffff-no-rj-mo",
            "width": 48,
            "height": 48
        },
        {
            "url": "//yt3.googleusercontent.com/ytc/AIdro_m9CJFVl3bEWvGnNnN4G9ErBO2lTpKePWCjx_FQtLWaDww=s76-c-k-c0x00ffffff-no-rj-mo",
            "width": 76,
            "height": 76
        }
    ],
    "accessibility": {
        "accessibilityData": {
            "label": "SomeOrdinaryGamers"
        }
    }
},
```
2026-08-02 21:09:15 -04:00
Fijxu
711817018a
chore: fix typo in .gitignore 2026-08-02 18:21:18 -04:00
Fijxu
e80fae77cc
chore: add invidious.o file to .gitignore 2026-08-02 17:58:10 -04:00
Fijxu
51723b6331
chore: remove pkg-config package from package.nix
This package makes it conflict with the dependencies needed to build
Invidious (openssl, libpcre, etc). crystalline can work perfectly
without it tho, but it was added in the first place because crystalline
was trying to invoke it.
2026-08-02 17:51:07 -04:00
Fijxu
d30a1f3e17
chore: remove -Dpreview_mt from Makefile as it has been deprecated by the Crystal compiler. (#5872)
Crystal 1.21.0 now features execution contexts, they do not longer support (and recommend) the -Dpreview_mt build flag. -Dpreview_mt also worked really bad and it made Invidious to hang on high load, so it was never useful.

https://crystal-lang.org/2026/07/16/1.21.0-released/#execution-contexts
2026-08-02 17:20:57 -04:00
Fijxu
54f20d01cb
Translations update from Hosted Weblate (#5474) 2026-08-02 17:13:33 -04:00
Fijxu
2acee823b5
chore: remove -Dpreview_mt from Makefile as it has been deprecated by the Crystal compiler.
Crystal 1.21.0 now features execution contexts, they do not longer support (and recommend) the `-Dpreview_mt` build flag. It also worked really bad and it made Invidious to hang on high load.
2026-08-02 16:54:22 -04:00
Hosted Weblate
e709fcfb49
Add Sign Languages translation
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Rafael Mexes <rafaelmexespangaubanyau01@gmail.com>
2026-08-02 22:30:05 +02:00
Hosted Weblate
dc381c7b02
Update Norwegian Bokmål translation
Update Norwegian Bokmål translation

Update Norwegian Bokmål translation

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Telaneo <post@telaneo.net>
2026-08-02 22:30:04 +02:00
Hosted Weblate
45f50b15ef
Update Alemannic translation
Update Alemannic translation

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Lenny Angst <lenny@familie-angst.ch>
2026-08-02 22:30:04 +02:00
Hosted Weblate
34beafeeec
Update Chinese (Simplified Han script) translation
Update Chinese (Simplified Han script) translation

Update Chinese (Simplified Han script) translation

Update Chinese (Simplified Han script) translation

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
2026-08-02 22:30:03 +02:00
Hosted Weblate
14866656bd
Update Chinese (Traditional Han script) translation
Update Chinese (Traditional Han script) translation

Update Chinese (Traditional Han script) translation

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Jeff Huang <s8321414@gmail.com>
2026-08-02 22:30:03 +02:00
Hosted Weblate
1cf00ac69b
Update Portuguese (Portugal) translation
Co-authored-by: António Oliveira <antonio.oliveira5487@gmail.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
2026-08-02 22:30:02 +02:00
Hosted Weblate
ed068d3d8c
Update Slovenian translation
Update Slovenian translation

Co-authored-by: Damjan Gerl <damjan@damjan.net>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
2026-08-02 22:30:02 +02:00
Hosted Weblate
602670f441
Update Korean translation
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: xrfmkrh <rF3nMd7sRKezjF2vcEQo@protonmail.com>
2026-08-02 22:30:01 +02:00
Hosted Weblate
9c39cadc6e
Update Albanian translation
Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update Albanian translation

Update translation files

Updated by "Remove blank strings" hook in Weblate.

Update Albanian translation

Update Albanian translation

Update Albanian translation

Co-authored-by: Andrea Toska <toskaandrea@gmail.com>
Co-authored-by: Besnik Bleta <besnik@programeshqip.org>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/invidious/translations/
Translation: Invidious/Invidious Translations
2026-08-02 22:30:01 +02:00
Hosted Weblate
d2d3d16b80
Update Finnish translation
Update Finnish translation

Update Finnish translation

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Patrik Selin <patrik.selin@gmail.com>
Co-authored-by: Tuomas Hietala <tuomas.hietala@iki.fi>
2026-08-02 22:30:01 +02:00
Hosted Weblate
e107081ecc
Update Persian translation
Co-authored-by: Danial Behzadi <dani.behzi@ubuntu.com>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
2026-08-02 22:30:00 +02:00
Hosted Weblate
cdec292bbe
Update Swedish translation
Update Swedish translation

Update Swedish translation

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Joel A <joeax910@student.liu.se>
Co-authored-by: bittin1ddc447d824349b2 <bittin@reimu.nl>
2026-08-02 22:30:00 +02:00
Hosted Weblate
476d05b7cc
Update French translation
Update French translation

Update French translation

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: I-I-IT <weblate.hut787@aleeas.com>
Co-authored-by: John Kindle <idp-portal.suse.com.dwindle414@aleeas.com>
Co-authored-by: Tristan B <tristanb0@users.noreply.hosted.weblate.org>
2026-08-02 22:29:59 +02:00
Hosted Weblate
783c99b266
Update Spanish translation
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Nicolás Pérez <ccnicolasperez@gmail.com>
2026-08-02 22:29:59 +02:00