/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>
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>
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>
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>
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>
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>
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>
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>
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>
* Revert "Fix disappearing end of the comments with emoji (#5587)"
This reverts commit 86c425b43f75dd1f22034bbfbd99476651661348.
* fix: fix rendered links and timestamps in video descriptions
* 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>
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"
}
}
},
```
Some YouTube videos like https://www.youtube.com/watch?v=Ajkr_Wg-k8g
had an non comment key that was inside the Array that contained some
comment information that Invidious parses (like comment_key and
toolbar_key), that being the `commentFilterContextViewModel` key, which
is just an indicator on how comments are sorted:
```
{
"commentThreadRenderer": { ... } <- comment information that is
handled by line 134 of youtube.cr
},
{
"commentFilterContextViewModel": {
"text": {
"content": "Top is selected, so you'll see featured comments"
},
"accessibility": {
"accessibilityData": {
"label": "Top is selected, so you'll see featured comments"
}
}
} <- Useless information, this is not a comment
}
```
* Add option to disable easy to abuse API endpoints
The API endpoints that will be disabled when this option are:
- /api/v1/videos
- /api/v1/clips
- /api/v1/transcripts
There is still API endponts that need some sort of validation or
connection/proxying to Invidious companion like
`/api/v1/captions` and `/api/v1/storyboards` since they also do a video
request to Invidious companion. I'm not sure if the `/next` API endpoint
could be used to gather that type of information, if so, that would be
better.
Closes#5599
* Rename configuration variable, add additional comment for the option
Saves an unnecessary redirect by using `www.youtube.com` on some parts of Invidious where `youtube.com` was used instead. youtube.com will redirect to www.youtube.com anyways.
Co-authored-by: janmoesen <@>
* Add support for alternative domains for Invidious cookies
* check if @@secure is already true before changing it's value
* Add alternative_domains config option example
* fix: Do not append query params `quality=medium` to videos that are about to premiere
Video premieres do not have `audio_streams` and they aren't `video.live_now == true` either,
therefore we skip the checks that are made for older videos (`if audio_streams.empty? && !video.live_now` closure)
if the video is a premiere.
This commit also adds the `microformat` field to the `info` instance
variable of the `Video` struct, since it's needed for the function
`Video#premiere_timestamp : Time?`. This is more like a quick fix than a
proper fix because in `Invidious::Videos::Parser#parse_video_info`,
`premiere_timestamp` is gathered from the `microformat` JSON Object but
is used to set the `published` hash key for the `params` variable.
The parsers and structs really need a rework :/
* Revert "fix: Do not append query params `quality=medium` to videos that are about to premiere"
This reverts commit 5cfc8dace82590ea6a41c849c9c39b1b7ba95fe7.
* chore: build premiere_timestamp using video_type and published time
Previous code use UTF-8 to count characters however Emojis are UTF-16 units.
This difference leads to misalignment of index offsets.
Co-authored-by: shiny-comic <shiny-comic@winPC>
* fix author verification in channels
Fixes https://github.com/iv-org/invidious/issues/5730
Author verification badge is not longer located in
`c4TabbedHeaderRenderer`. It may be deprecated.
* Also detect AUDIO_BADGE for verified author
* feat: add support for /pl_c/ images
This path can be found on Podcast images.
* add support for /pl_c and /tvfilm_banner paths
* add support for /pl_c and /tvfilm_banner paths 2
* remove leftover comment
* fix: fix channel videos and playlists on searches
Channel videos are now encapsulated in a `lockupViewModel`.
There is 3 types of content that can be inside a `lockupViewModel`:
- LOCKUP_CONTENT_TYPE_VIDEO
- LOCKUP_CONTENT_TYPE_PLAYLIST
- LOCKUP_CONTENT_TYPE_PODCAST
This commit parses `LOCKUP_CONTENT_TYPE_VIDEO`, `LOCKUP_CONTENT_TYPE_PLAYLIST`, `LOCKUP_CONTENT_TYPE_PODCAST` types
to fix videos in channels, playlists in channels, podcast in channels, and other parts of Invidious were playlists and videos are displayed.
* remove unused variable `author_verified`
* fix parsing for podcasts
For some reason, Podcasts contains an empty JSON Object that we have to
skip, therefore we just iterate metadataRows until finding metadataParts
since metadataRows will not always contain a single Object.
* fix length_seconds for channel videos
* fix playlists parsing for playlists without metadataParts
On some channels like MrBeast, metadataParts is absent, missing the
author information, this is intended behaviour by Youtube since there is
no author information attached to them.
Example URL: https://www.youtube.com/channel/UCX6OQ3DkcsbYNE6H8uQQuVA/playlists
* restore author_verified functionality
* more robust metadata_parts parsing
Videos that have two or more authors (in collaborations), have their
author information in JSON Objects inside metadataParts, alongside with
their view count and their published date, therefore, we need to iterate
the metadataParts array and do some filtering based on the content of
each JSON Object to find the view count and published date for some
videos.
Example:
```json
"metadataParts": [
{
"text": {
"content": "Veritasium"
},
"icon": {
"name": "CHECK_CIRCLE_FILLED",
"height": 14,
"width": 14,
"accessibilityLabel": "Verified"
}
},
{
"text": {
"content": "and Linus Tech Tips"
},
"icon": {
"name": "CHECK_CIRCLE_FILLED",
"height": 14,
"width": 14,
"accessibilityLabel": "Verified"
}
},
{
"text": {
"content": "10M"
},
"accessibilityLabel": "10 million views"
},
{
"text": {
"content": "1y ago"
}
}
]
```
* improve playlist metadataRows and metadataParts parsing for channel playlists
* apply ameba suggestion
* Also parse lessons for playlists that are a course
* Playlists: fix parsing error when some videos are paid for in a course
* Remove redundant casting to string
fix rebase error
Co-Authored-By: syeopite <70992037+syeopite@users.noreply.github.com>
* Fix rebase issues
---------
Co-authored-by: syeopite <70992037+syeopite@users.noreply.github.com>
When switching between Listen and Watching the timestamp in the url of
the listen of watch button is now updated automatically.
This means if you switch between listening and viewing you keep in sync
with time.
* Remove sort by rating and date in video search filters
Closes https://github.com/iv-org/invidious/issues/5626
* Remove check of protobug generation of rating and date sort filters in Invidious spec