1
1
mirror of https://github.com/iv-org/invidious.git synced 2024-11-22 17:04:10 +03:00

Documentation moved + Remove everything except the instance list since it's still used by instance.invidio.us

TheFrenchGhosty 2020-11-30 20:47:21 +01:00
parent d81a960194
commit 62008631e5
18 changed files with 1 additions and 1884 deletions

938
API.md

@ -1,938 +0,0 @@
### Language
All endpoints that return a JSON body support `&hl=LANGUAGE` for translating fields into the desired language. A list of languages are provided in [List of URL parameters](./List-of-URL-parameters).
### Pretty
All endpoints that return a JSON body support `&pretty=1` for printing the response as formatted JSON.
### Fields
All endpoints that return a JSON body support the [fields API](https://developers.google.com/youtube/v3/getting-started#fields) for specifying desired fields to reduce bandwidth consumption. This can be used by adding `&fields=FIELDS` with the desired fields, for example [`/api/v1/videos/aqz-KE-bpKQ?fields=videoId,title,description&pretty=1`](https://invidio.us/api/v1/videos/aqz-KE-bpKQ?fields=videoId,title,description&pretty=1).
##### GET `/api/v1/stats`
> Schema:
```javascript
{
"version": String,
"software": {
"name": "invidious",
"version": String,
"branch": String
},
"openRegistrations": Bool,
"usage": {
"users": {
"total": Int32,
"activeHalfyear": Int32,
"activeMonth": Int32
}
},
"metadata": {
"updatedAt": Int64,
"lastChannelRefreshedAt": Int64
}
}
```
##### GET `/api/v1/videos/:id`
> Schema:
```javascript
{
"title": String,
"videoId": String,
"videoThumbnails": [
{
"quality": String,
"url": String,
"width": Int32,
"height": Int32
}
],
"description": String,
"descriptionHtml": String,
"published": Int64,
"publishedText": String,
"keywords": Array(String),
"viewCount": Int64,
"likeCount": Int32,
"dislikeCount": Int32,
"paid": Bool,
"premium": Bool,
"isFamilyFriendly": Bool,
"allowedRegions": Array(String),
"genre": String,
"genreUrl": String,
"author": String,
"authorId": String,
"authorUrl": String,
"authorThumbnails": [
{
"url": String,
"width": Int32,
"height": Int32
}
],
"subCountText": String,
"lengthSeconds": Int32,
"allowRatings": Bool,
"rating": Float32,
"isListed": Bool,
"liveNow": Bool,
"isUpcoming": Bool,
"premiereTimestamp": Int64?,
"hlsUrl": String?,
"adaptiveFormats": [
{
"index": String,
"bitrate": String,
"init": String,
"url": String,
"itag": String,
"type": String,
"clen": String,
"lmt": String,
"projectionType": Int32,
"container": String,
"encoding": String,
"qualityLabel": String?,
"resolution": String?
}
],
"formatStreams": [
{
"url": String,
"itag": String,
"type": String,
"quality": String,
"container": String,
"encoding": String,
"qualityLabel": String,
"resolution": String,
"size": String
}
],
"captions": [
{
"label": String,
"languageCode": String,
"url": String
}
],
"recommendedVideos": [
{
"videoId": String,
"title": String,
"videoThumbnails": [
{
"quality": String,
"url": String,
"width": Int32,
"height": Int32
}
],
"author": String,
"lengthSeconds": Int32,
"viewCountText": String
}
]
}
```
Parameters:
```
region: ISO 3166 country code (default: "US")
```
##### GET `/api/v1/annotations/:id`
Parameters:
```
source: "archive", "youtube" (default: "archive")
```
Returns annotation XML from YouTube's `/annotations_invideo` endpoint. Alternatively it provides access to legacy annotation data using [this collection](https://archive.org/details/youtubeannotations) on archive.org.
##### GET `/api/v1/comments/:id`
> Schema:
```javascript
{
"commentCount": Int32?,
"videoId": String,
"comments": [
{
"author": String,
"authorThumbnails": [
{
"url": String,
"width": Int32,
"height": Int32
}
],
"authorId": String,
"authorUrl": String,
"isEdited": Bool,
"content": String,
"contentHtml": String,
"published": Int64,
"publishedText": String,
"likeCount": Int32,
"commentId": String,
"authorIsChannelOwner": Bool,
"creatorHeart": {
"creatorThumbnail": String,
"creatorName": String
}?,
"replies": {
"replyCount": Int32,
"continuation": String
}?
}
],
"continuation": String?
}
```
Parameters:
```
sort_by: "top", "new" (default: top)
source: "youtube", "reddit" (default: youtube)
continuation: String
```
##### GET `/api/v1/insights/:id`
**Will always return 510: `YouTube has removed publicly-available analytics`\***
> Schema:
```javascript
{
"viewCount": Int64,
"timeWatchedText": String,
"subscriptionsDriven": Int32,
"shares": Int32,
"avgViewDurationSeconds": Int32,
"graphData": {
// ...
}
}
```
##### GET `/api/v1/captions/:id`
> Schema:
```javascript
{
"captions": [
{
"label": String,
"languageCode": String,
"url": String
}
]
}
```
Parameters:
```
label: String
lang: String
tlang: String
region: ISO 3166 country code (default: "US")
```
A request with `label` will return the selected captions in WebVTT format.
Captions can also be selected with an ISO `lang`, e.g. &lang=en, `tlang` will auto-translate from English into the requested language (if English captions are available).
##### GET `/api/v1/trending`
> Schema:
```javascript
[
{
"title": String,
"videoId": String,
"videoThumbnails": [
{
"quality": String,
"url": String,
"width": Int32,
"height": Int32
}
],
"lengthSeconds": Int32,
"viewCount": Int64,
"author": String,
"authorId": String,
"authorUrl": String,
"published": Int64,
"publishedText": String,
"description": String,
"descriptionHtml": String,
"liveNow": Bool,
"paid": Bool,
"premium": Bool
}
]
```
Parameters:
```
type: "music", "gaming", "news", "movies"
region: ISO 3166 country code (default: "US")
```
##### GET `/api/v1/top`
> Schema:
```javascript
[
{
"title": String,
"videoId": String,
"videoThumbnails": [
{
"quality": String,
"url": String,
"width": Int32,
"height": Int32
}
],
"lengthSeconds": Int32,
"viewCount": Int64,
"author": String,
"authorId": String,
"authorUrl": String,
"published": Int64,
"publishedText": String,
"description": String,
"descriptionHtml": String
}
]
```
##### GET `/api/v1/popular`
> Schema:
```javascript
[
{
"type": "shortVideo",
"title": String,
"videoId": String,
"videoThumbnails": [
{
"quality": String,
"url": String,
"width": Int32,
"height": Int32
}
],
"lengthSeconds": Int32,
"viewCount": Int64,
"author": String,
"authorId": String,
"authorUrl": String,
"published": Int64,
"publishedText": String
}
]
```
##### GET `/api/v1/channels/:ucid`
> Schema:
```javascript
{
"author": String,
"authorId": String,
"authorUrl": String,
"authorBanners": [
{
"url": String,
"width": Int32,
"height": Int32
}
],
"authorThumbnails": [
{
"url": String,
"width": Int32,
"height": Int32
}
],
"subCount": Int32,
"totalViews": Int64,
"joined": Int64,
"paid": Bool,
"autoGenerated": Bool,
"isFamilyFriendly": Bool,
"description": String,
"descriptionHtml": String,
"allowedRegions": Array(String),
"latestVideos": [
{
"title": String,
"videoId": String,
"author": String,
"authorId": String,
"authorUrl": String,
"videoThumbnails": [
{
"quality": String,
"url": String,
"width": Int32,
"height": Int32
}
],
"description": String,
"descriptionHtml": String,
"viewCount": Int64,
"published": Int64,
"publishedText": String,
"lengthSeconds": Int32,
"paid": Bool,
"premium": Bool
}
],
"relatedChannels": [
{
"author": String,
"authorId": String,
"authorUrl": String,
"authorThumbnails": [
{
"url": String,
"width": Int32,
"height": Int32
}
]
}
]
}
```
Parameters:
```
sort_by: "newest", "oldest", "popular" (default: newest)
```
Note that a channel's username (if it doesn't include spaces) is also valid in place of `ucid`, e.g. `/api/v1/channels/BlenderFoundation`.
##### GET `/api/v1/channels/:ucid/videos`, `/api/v1/channels/videos/:ucid`
> Schema:
```javascript
[
{
title: String,
videoId: String,
author: String,
authorId: String,
authorUrl: String,
videoThumbnails: [
{
quality: String,
url: String,
width: Int32,
height: Int32
}
],
description: String,
descriptionHtml: String,
viewCount: Int64,
published: Int64,
publishedText: String,
lengthSeconds: Int32
paid: Bool,
premium: Bool
}
]
```
Parameters:
```
page: Int32
sort_by: "newest", "oldest", "popular" (default: newest)
```
##### GET `/api/v1/channels/:ucid/latest`, `/api/v1/channels/latest/:ucid`
```javascript
[
{
title: String,
videoId: String,
authorId: String,
authorUrl: String,
videoThumbnails: [
{
quality: String,
url: String,
width: Int32,
height: Int32
}
],
description: String,
descriptionHtml: String,
viewCount: Int64,
published: Int64,
publishedText: String,
lengthSeconds: Int32
paid: Bool,
premium: Bool
}
]
```
##### GET `/api/v1/channels/playlists/:ucid`, `/api/v1/channels/:ucid/playlists`
```javascript
{
"playlists": [
{
"title": String,
"playlistId": String,
"author": String,
"authorId": String,
"authorUrl": String,
"videoCount": Int32,
"videos": [
{
"title": String,
"videoId": String,
"lengthSeconds": Int32,
"videoThumbnails": [
{
"quality": String,
"url": String,
"width": Int32,
"height": Int32
}
]
}
]
],
"continuation": String?
}
```
Parameters:
```
continuation: String
sort_by: "oldest", "newest", "last"
```
##### GET `/api/v1/channels/comments/:ucid`, `/api/v1/channels/:ucid/comments`
```javascript
{
"authorId": String,
"comments": [
{
"author": String,
"authorThumbnails": [
"url": String,
"width": Int32,
"height": Int32
],
"authorId": String,
"authorUrl": String,
"isEdited": Bool,
"content": String,
"contentHtml": String,
"published": Int64,
"publishedText": String,
"likeCount": Int32,
"commentId": String,
"authorIsChannelOwner": Bool,
"creatorHeart": {
"creatorThumbnail": String,
"creatorName": String
}?,
"replies": {
"replyCount": Int32,
"continuation": String
}?,
"attachment": Attachment?
}
],
"continuation": String?
}
```
The `authorId` for top-level comments will always(?) be the same as the requested channel. Top-level comments will also have an optional `attachment`, which can be one of:
```javascript
{
"type": "image",
"imageThumbnails": [
{
"url": String,
"width": Int32,
"height": Int32
}
]
}
```
```javascript
{
"type": "video",
"title": String,
"videoId": String,
"videoThumbnails": [
{
"quality": String,
"url": String,
"width": Int32,
"height": Int32
}
],
"lengthSeconds": Int32,
"author": String,
"authorId": String,
"authorUrl": String,
"published": Int64,
"publishedText": String,
"viewCount": Int64,
"viewCountText": String
}
```
```javascript
{
"type": "unknown",
"error": "Unrecognized attachment type."
}
```
Some attachments may only have a `type` and `error`, similar to the above. Attachments will *only* be present on top-level comments.
Parameters:
```
continuation: String
```
##### GET `/api/v1/channels/search/:ucid`
> Schema:
```javascript
[
{
type: "video",
title: String,
videoId: String,
author: String,
authorId: String,
authorUrl: String,
videoThumbnails: [
{
quality: String,
url: String,
width: Int32,
height: Int32
}
],
description: String,
descriptionHtml: String,
viewCount: Int64,
published: Int64,
publishedText: String,
lengthSeconds: Int32,
liveNow: Bool,
paid: Bool,
premium: Bool
},
{
type: "playlist",
title: String,
playlistId: String,
author: String,
authorId: String,
authorUrl: String,
videoCount: Int32,
videos: [
{
title: String,
videoId: String,
lengthSeconds: Int32,
videoThumbnails: [
{
quality: String,
url: String,
width: Int32,
height: Int32
}
]
}
]
},
{
type: "channel",
author: String,
authorId: String,
authorUrl: String,
authorThumbnails: [
{
url: String,
width: Int32,
height: Int32
}
],
subCount: Int32,
videoCount: Int32,
description: String,
descriptionHtml: String
}
];
```
Parameters:
```
q: String
page: Int32
```
##### GET `/api/v1/search/suggestions`
> Schema:
```javascript
{
"query": String,
"suggestions": Array(String)
}
```
Parameters:
```
q: String
```
##### GET `/api/v1/search`
> Schema:
```javascript
[
{
type: "video",
title: String,
videoId: String,
author: String,
authorId: String,
authorUrl: String,
videoThumbnails: [
{
quality: String,
url: String,
width: Int32,
height: Int32
}
],
description: String,
descriptionHtml: String,
viewCount: Int64,
published: Int64,
publishedText: String,
lengthSeconds: Int32,
liveNow: Bool,
paid: Bool,
premium: Bool
},
{
type: "playlist",
title: String,
playlistId: String,
author: String,
authorId: String,
authorUrl: String,
videoCount: Int32,
videos: [
{
title: String,
videoId: String,
lengthSeconds: Int32,
videoThumbnails: [
{
quality: String,
url: String,
width: Int32,
height: Int32
}
]
}
]
},
{
type: "channel",
author: String,
authorId: String,
authorUrl: String,
authorThumbnails: [
{
url: String,
width: Int32,
height: Int32
}
],
subCount: Int32,
videoCount: Int32,
description: String,
descriptionHtml: String
}
];
```
Parameters:
```
q: String
page: Int32
sort_by: "relevance", "rating", "upload_date", "view_count"
date: "hour", "today", "week", "month", "year"
duration: "short", "long"
type: "video", "playlist", "channel", "all", (default: video)
features: "hd", "subtitles", "creative_commons", "3d", "live", "purchased", "4k", "360", "location", "hdr" (comma separated: e.g. "&features=hd,subtitles,3d,live")
region: ISO 3166 country code (default: "US")
```
##### GET `/api/v1/playlists/:plid`
> Schema:
```javascript
{
"title": String,
"playlistId": String,
"author": String,
"authorId": String,
"authorThumbnails": [
{
"url": String,
"width": String,
"height": String
}
],
"description": String,
"descriptionHtml": String,
"videoCount": Int32,
"viewCount": Int64,
"updated": Int64,
"videos": [
{
"title": String,
"videoId": String,
"author": String,
"authorId": String,
"authorUrl": String,
"videoThumbnails": [
{
"quality": String,
"url": String,
"width": Int32,
"height": Int32
}
],
"index": Int32,
"lengthSeconds": Int32
}
]
}
```
Parameters:
```
page: Int32
```
##### GET `/api/v1/mixes/:rdid`
> Schema:
```javascript
{
title: String,
mixId: String,
videos: [
{
title: String,
videoId: String,
author: String,
authorId: String,
authorUrl: String,
videoThumbnails: [
{
quality: String,
url: String,
width: Int32,
height: Int32
}
],
index: Int32,
lengthSeconds: Int32
}
]
}
```

@ -1,22 +0,0 @@
Download ViolentMonkey for your Browser:
[Firefox](https://addons.mozilla.org/en-US/firefox/addon/violentmonkey/)
[Chrome and Chromium](https://chrome.google.com/webstore/detail/violentmonkey/jinjaccalgkegednnccohejagnlnfdag)
[Others](https://violentmonkey.github.io/get-it/)
Than add the following script in ViolentMonkey. It will always add `&local=true` to the end of the video URL.
```
// ==UserScript==
// @name Invidious Proxy automatically
// @match *://*.invidio.us/watch?v=*
// @run-at document-start
// @grant none
// ==/UserScript==
if (!(/[?&]local=/).test(location.search) && !(/[?&]quality=dash/).test(location.search)) {
location.search += (location.search ? "&" : "?") + "local=true";
}
```
You can also enable this by checking `Proxy videos?` in your preferences.

@ -1,24 +0,0 @@
This is a very basic config, secured with Let's Encrypt. Any log is disabled by default. Do not forget to replace `ServerName` with your domain.
```
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName invidious.domain.tld
ServerAdmin admin@localhost
ProxyPreserveHost On
ProxyRequests off
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
# ErrorLog /var/log/apache2/invidious.domain.tld/error.log
CustomLog /dev/null combined
RewriteEngine on
SSLCertificateFile /etc/letsencrypt/live/invidious.domain.tld/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/invidious.domain.tld/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/invidious.domain.tld/chain.pem
</VirtualHost>
</IfModule>
```

@ -1,418 +0,0 @@
All endpoints under namespace `/api/v1/auth` require authentication.
Authentication can be in one of two forms:
- A `Cookie: <SID>` header (for logged in users)
- An `Authentication: Bearer <TOKEN>` (recommended)
A new token can be generated from `/authorize_token` with the given parameters:
```
scopes: Comma-separated list of scopes
callback_url: URL to redirect to with generated token
expire: Int64 how long a given token should be valid (in seconds)
```
Each `scope` has the following format:
```
METHOD1;METHOD2...:ENDPOINT(*)?
```
Where `METHOD` can be one of `GET`, `POST`, `PUT`, `DELETE`, `PATCH`.
An `ENDPOINT` can be any of the documented endpoints below.
Examples:
- `POST:playlists*`: authorizes `POST` methods to _any_ endpoint under `/api/v1/auth/playlists` (`/api/v1/auth/playlists`, `/api/v1/playlists/:id/videos`, etc.)
- `:playlists/*`: authorizes \_any method to endpoints under `/api/v1/auth/playlists/` (`/api/v1/auth/playlists/:id`, `/api/v1/playlists/:id/videos`, etc.)
- `GET:playlists/IVPAAAAAAA`: authorizes `GET` only to playlist `IVPAAAAAA`.
- `:preferences`: authorizes _any_ method to `/api/v1/auth/preferences`
- `GET;POST:preferences`: authorizes `GET` or `POST` to `/api/v1/auth/preferences`
When a `callback_url` is specified, after a user has authorized a token with the desired `scopes`, a GET request will be made to the `callback_url` with the token URL-escaped and appended as `token=TOKEN`.
##### GET `/api/v1/auth/feed`
Get subscription feed for the authenticated user.
Parameters:
```
max_results: Int32
page: Int32
```
> Schema:
```javascript
{
"notifications": [
{
"type": "shortVideo",
"title": String,
"videoId": String,
"videoThumbnails": [
{
"quality": String,
"url": String,
"width": Int64,
"height": Int64
}
],
"lengthSeconds": Int64,
"author": String,
"authorId": String,
"authorUrl": String,
"published": Int64,
"publishedText": String,
"viewCount": Int64
}
],
"videos": [
{
"type": "shortVideo",
"title": String,
"videoId": String,
"videoThumbnails": [
{
"quality": String,
"url": String,
"width": Int64,
"height": Int64
}
],
"lengthSeconds": Int64,
"author": String,
"authorId": String,
"authorUrl": String,
"published": Int64,
"publishedText": String,
"viewCount": Int64
}
]
}
```
##### GET `/api/v1/auth/notifications`
Parameters:
```
topics: Array(String) (comma separated: e.g. "UCID1,UCID2) limit of 1000 topics
since: Int64, timestamp
```
Provides an [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) for receiving changes from each `topic` in `topics`. Currently the only supported topic-type is `ucid`, which will return an updated video object whenever the given channel uploads a video.
Important to note is that an event will also be sent when a channel _changes_ an already uploaded video, for example changing description or title.
Each event is a JSON object with the same schema as `/api/v1/videos`. The `fields` API can be used, which will be applied to each object.
A `debug` topic can also provided which will return a (psuedo-)randomly selected video every minute.
`since` will return all videos uploaded since `TIMESTAMP`, with a limit of the 15 most recent videos from each topic.
More details in [#469](https://github.com/iv-org/invidious/issues/469).
##### POST `/api/v1/auth/notifications`
Same as above `GET` endpoint, however `topics` is moved into post body as `Content-Type: application/x-www-form-urlencoded`.
##### GET `/api/v1/auth/playlists`
Get list of playlists for the given user.
> Schema:
```javascript
[
{
"type": "invidiousPlaylist",
"title": String,
"playlistId": String,
"author": String,
"authorId": null,
"authorUrl": null,
"authorThumbnails": [],
"description": String,
"descriptionHtml": String,
"videoCount": Int32,
"viewCount": 0,
"updated": Int64,
"isListed": Boolean,
"videos": [
{
"title": String,
"videoId": String,
"author": String,
"authorId": String,
"authorUrl": String,
"videoThumbnails": [
{
"quality": String,
"url": String,
"width": Int32,
"height": Int32
}
],
"index": Int32,
"indexId": String,
"lengthSeconds": Int32
}
]
}
]
```
##### POST `/api/v1/auth/playlists`
`Content-Type: application/json`
Create new playlist.
Example request body:
```javascript
{
"title": String,
"privacy": "private"
}
```
`privacy` can be any of: `public`, `unlisted`, `private`
If successful, returns 201, a link to the created resource as a `Location` header, and the following response:
```javascript
{
"title": String,
"playlistId": String
}
```
##### GET `/api/v1/auth/playlists/:id`
Returns same result as unauthenticated `/api/v1/playlists/:id`.
Important to note is that if the requested playlist is marked as `private`, it will return an error if the request is not authenticated as the playlist's author.
##### PATCH `/api/v1/auth/playlists/:id`
`Content-Type: application/json`
Modify a playlist's `description`, `title`, `description`, or `privacy`.
Example request body:
```javascript
{
"title": String,
"description": String,
"privacy": "private"
}
```
`privacy` can be any of: `public`, `unlisted`, `private`
Will return 204 on success.
##### DELETE `/api/v1/auth/playlists/:id`
Delete a given playlist `:id`.
Will return 204 on success.
##### POST `/api/v1/auth/playlists/:id/videos`
`Content-Type: application/json`
Add a video to the given playlist `:id`.
Example request body:
```javascript
{
"videoId": String
}
```
Returns a 201 on success with the following schema:
```javascript
{
"title": String,
"videoId": String,
"author": String,
"authorId": String,
"authorUrl": String,
"videoThumbnails": [
{
"quality": String,
"url": String,
"width": Int32,
"height": Int32
}
]
}
```
##### DELETE `/api/v1/auth/playlists/:id/videos/:index`
Delete a video from the given playlist `:id` with `indexId` `:index`.
Will return 204 on success.
##### GET `/api/v1/auth/preferences`
Get preferences for authenticated user.
> Schema:
```javascript
{
"annotations": false,
"annotations_subscribed": false,
"autoplay": false,
"captions": [
"",
"",
""
],
"comments": [
"youtube",
""
],
"continue": false,
"continue_autoplay": true,
"dark_mode": "light",
"latest_only": false,
"listen": false,
"local": false,
"locale": "en-US",
"max_results": 40,
"notifications_only": false,
"player_style": "invidious",
"quality": "hd720",
"default_home": "Popular",
"feed_menu": [
"Trending",
"Playlists"
],
"related_videos": true,
"sort": "published",
"speed": 1.0,
"thin_mode": false,
"unseen_only": false,
"video_loop": false,
"volume": 100
}
```
##### POST `/api/v1/auth/preferences`
`Content-Type: application/json`
Patch user preferences.
Example body:
```javascript
{
"speed": 2.0,
"volume": 10
}
```
##### GET `/api/v1/auth/subscriptions`
Get user's subscriptions.
> Schema:
```javascript
[
{
"author": String,
"authorId": String
}
]
```
##### POST `/api/v1/auth/subscriptions/:ucid`
`Content-Type: application/json`
Add a given `ucid` to a user's subscriptions.
Will return 204 on success.
##### DELETE `/api/v1/auth/subscriptions/:ucid`
Removes a given `ucid` from a user's subscriptions.
Will return 204 on success.
##### GET `/api/v1/auth/tokens`
Get a list of tokens for the authenticated user.
> Schema:
```javascript
[
{
"session": String,
"issued": Int64
}
]
```
##### POST `/api/v1/auth/tokens/register`
`Content-Type: application/json`
Create a new token for the authenticated user.
Example request body:
```javascript
{
"scopes": Array(String), // Each scope has same format as each scope in `/authorize_token`
"callbackUrl": String?,
"expire": Int64
}
```
Returns a 200 on success with the newly created token as the response body.
Example response:
```javascript
{
"session":"v1:YUwKEL1XwHQzp7-AAAAAAAAAAAAAAAAAA=",
"scopes":["GET:notifications"],
"signature":"jNYdAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAXGb__2Gv-w="
}
```
##### POST `/api/v1/auth/tokens/unregister`
`Content-Type: application/json`
Revoke a token for the authenticated user.
Example request:
```javascript
{
"session": "v1:YUwKEL1XwHQzp7-AAAAAAAAAAAAAAAAAA="
}
```
Returns 204 on success.

@ -1,71 +0,0 @@
### What can be configured and what are these configuration options?
The configuration file is located at [invidious/config/config.yml](https://github.com/iv-org/invidious/blob/master/config/config.yml).
- `channel_threads` (default `1`) Number of threads to use for crawling videos from channels
- `feed_threads` (default `1`) Number of threads to use for refreshing subscription feeds
```
db:
user: kemal # your database user
password: kemal # your database password
host: localhost # database host
port: 5432 # postgres port
```
- `full_refresh` (default `false`) When crawling channel videos, threads should refresh *all* videos uploaded by a channel
- `https_only` (default `false`) Used to tell Invidious it is accessed via https, set to `true` if you have for example a reverse proxy with a ssl certificate
- `hmac_key` (default `nil`) Signing key for CSRF tokens (when `nil` is randomly generated on startup, can be any random string)
- `domain` (default `nil`) Domain to use for providing `self` links in RSS feeds, issuing cookies, etc.
- `use_pubsub_feeds` (default `false`) Use server-side notifications provided by [YouTube](https://developers.google.com/youtube/v3/guides/push_notifications). Requires `domain` and `hmac_key` to be set
- `default_home` (default `"Top"`) Default home page **Moved into `default_user_preferences`**
- `feed_menu` (default `["Popular", "Top", "Trending", "Subscriptions"]`) Order of tabs on feed menu **Moved into `default_user_preferences`**
- `top_enabled` (default `true`) Whether top endpoints should be enabled (better privacy for smaller instances)
- `captcha_enabled` (default `true`) Determine if CAPTCHA should be required for registration
- `login_enabled` (default `true`) Whether users should be able to login
- `registration_enabled` (default `true`) Whether new users should be able to register
- `statistics_enabled` (default `false`) Whether statistics should be available from `/api/v1/stats`
- `admins` (default `[]`) List of user IDs that have access to administrator preferences
- `external_port` (default `nil`) Invidious should supply links to a different port (if running behind a proxy, for example). PubSub notifications (if enabled) will also be sent to this port
- `default_user_preferences` (default [`ConfigPreferences`](https://github.com/iv-org/invidious/blob/master/src/invidious/helpers/helpers.cr#L127)) Default preferences to use for new and unregistered users, see [#415](https://github.com/iv-org/invidious/issues/415)
- `dmca_content` (default `[]`) For compliance with DMCA requests, disables download widget for list of video IDs
- `check_tables` (default `false`) Check table integrity, automatically try to add any missing columns, create columns, etc.
- `cache_annotations` (default `false`) Cache annotations requested from IA, will not cache empty annotations or annotations that only contain cards
- `banner` (default `nil`) Optional banner to be displayed along top of page for announcements, etc.
- `hsts` (default `true`) For HTTP Strict Transport Security
- `disable_proxy` (default `false`) Disable proxy option serverwide (options: 'dash', 'livestreams', 'downloads', 'local')
- `force_resolve` (default `nil`) Force IPv4 or IPv6 connection to Google (options: 'ipv4', 'ipv6') see [#811](https://github.com/iv-org/invidious/issues/811)
- `pool_size` (default `100`) Pool size for HTTP connections for youtube.com and ytimg.com (each domain has a separate pool of `pool_size`)
- `admin_email` (default `omarroth@protonmail.com`) Email provided to users for bug reports
- `port` (default `3000`) Default port for HTTP server
- `host_binding` (default `0.0.0.0`) Default host for HTTP server
- `cookies` (default ``) Cookies to be used when connecting to YouTube
- `captcha_key` (default `nil`) [Anti-Captcha](https://anti-captcha.com/) API key for solving YouTube CAPTCHAs, see [#886](https://github.com/iv-org/invidious/issues/886).

@ -1,23 +0,0 @@
Invidious needs one PostgreSQL database which has the following tables.
- `annotations` Caches annotation data if `cache_annotations` is enabled in [`config.yml`](./Configuration)
- `channel_videos` Stores truncated video info, used to create user feeds
- `channels` Stores UCID and author name
- `nonces` Keeps track of tokens issued to prevent CSRF
- `users` Stores user info, such as preferences, username, subscriptions
- `session_ids` Keeps track of user sessions
- `videos` Stores video cache, used to create "top" page
The table `videos` grows a lot and needs the most storage. You can clean it up using following commands:
```bash
$ sudo -i -u postgres
$ psql invidious -c "DELETE FROM nonces * WHERE expire < current_timestamp"
$ psql invidious -c "TRUNCATE TABLE videos"
$ exit
```
For regular maintenance you should add a cronjob for these commands
```bash
@weekly psql invidious -c "DELETE FROM nonces * WHERE expire < current_timestamp" > /dev/null
@weekly psql invidious -c "TRUNCATE TABLE videos" > /dev/null
```

@ -1,25 +0,0 @@
### Browser extensions for Invidious
- [Privacy Redirect](https://github.com/SimonBrazell/privacy-redirect): Redirects YouTube to Invidious, Twitter to Nitter, and Instagram to Bibliogram. [Source](https://github.com/SimonBrazell/privacy-redirect) / [Firefox](https://addons.mozilla.org/en-US/firefox/addon/privacy-redirect/) / [Chrome](https://chrome.google.com/webstore/detail/privacy-redirect/pmcmeagblkinmogikoikkdjiligflglb)
- [SponsorBlock](https://github.com/ajayyy/SponsorBlock): A crowd-sourced extension to skip sponsorships. Support invidious instances if enabled in the options (Available for Chrome and Firefox).
- [Invidition](https://addons.mozilla.org/en-US/firefox/addon/invidition/): Firefox extension that redirects YouTube links and embeds to their Invidious counterpart without any call to YouTube. [(Source)](https://codeberg.org/Booteille/Invidition) (**deprecated**).
- [Alternate Tube Redirector](https://addons.mozilla.org/en-US/firefox/addon/alternate-tube-redirector/): Firefox extension to automatically open YouTube Videos on alternate sites like Invidious or Hooktube. [(Source)](https://gitlab.com/2vek/alternate-tube-redirector/).
- [Invidious Copy URL](https://github.com/recette-lemon/invidious-copy-url/): Adds context menu options on Invidious to copy shortened YouTube .URL at current time or not (Requires using developer mode in Chrome or a developer version of Firefox).
- [View on Invidious](https://omar.yt/722e5c15832840fe1ae8830b7c590254b9e0a45c/invidious-bookmarklet.html): View page on Invidious (bookmarklet).
- [Inviduration](https://addons.mozilla.org/en-US/firefox/addon/inviduration/): Shows total duration of playlists on Invidious. [(Source)](https://github.com/rsapkf/inviduration).
### Userscripts for Invidious.
- [Invidious Redirect](https://greasyfork.org/en/scripts/370461-invidious-redirect): Redirects YouTube URLs to Invidio.us.
- [YouTube to Invidious](https://greasyfork.org/en/scripts/375264-youtube-to-invidious): Scans current page for YouTube embeds and replace with Invidious.
- [No-Youtube](https://github.com/mperez01/no-youtube): Userscript to replace youtube links to invidio.us.
- [Invidious Audio Mode](https://greasyfork.org/en/scripts/397700-invidious-audio-mode): Adds a headphone icon next to all video links. Handy for those that just want to stream audio and not video.
- [FYTE](https://greasyfork.org/en/scripts/9252-fyte-fast-youtube-embedded-player): Replace all YouTube embeds on a page with the video's thumbnail. Click on the thumbnail to play the video. Invidious is supported in the Options panel.
### Extensions that integrate Invidious into other programs and apps
- [UntrackMe](https://f-droid.org/en/packages/app.fedilab.nitterizeme/): Android app to rewrite YouTube links to Invidious. Can optionally play videos in the app as well.
- [iPhone Redirector Shortcut](https://www.icloud.com/shortcuts/6bbf26d989cf4d07a5fe1626efbc0950): Automatically open YouTube videos in Invidious (iPhone shortcut).
- [FreshRSS Extension](https://github.com/tmiland/freshrss-invidious): A FreshRSS extension to directly embed videos from Invidious channel feeds.
- [Kodi add-on](https://github.com/TheAssassin/kodi-invidious-plugin): Watch YouTube videos in the Kodi media center, using the Invidious API. Privacy-friendly alternative to the YouTube API add-on.
- [Another Kodi add-on](https://github.com/lekma/plugin.video.invidious)...seems to have been more recently updated than the above.
### Utilities for Invidious
- [Invidious-Updater (And Installer)](https://github.com/tmiland/Invidious-Updater): Automatic update script for Invidious.

@ -1,21 +0,0 @@
## Geoblocking
Sometimes you may notice that you cannot watch a video on Invidious. This is because YouTube is geoblocking, i.e. preventing access to videos based on your geographical location.
If "Proxy videos?" setting is enabled, then Invidious will proxy videos through itself, so the stream will be routed like this:
> YouTube → Invidious/server → Client/browser
If a video is blocked where the instance is hosted, then the route would be this:
> YouTube → Proxy server → Invidious/server → Client/browser
The current system works by cycling through proxies in different regions, and finding one where the video is not blocked.
The reason geoblocked videos may take a long time to load is because Invidious would have to cycle through all known proxy servers until it finds one that is able to play back the video.
If "Proxy videos?" setting is disabled, then the stream would be routed like this:
> YouTube → Client/browser
## Video quality and DASH
On Invidious you often don't have the same quality options as on YouTube. This is because the audio and video streams are separated and Invidious currently can't sync them together.
DASH is a streaming technique used by YouTube to provide resolutions higher than 720p by providing multiple files for a client to use depending on network and user preferences.
You can enable DASH by selecting the appropriately named video quality in the settings or by appending `&quality=dash` to the end of a video's URL. With this option enabled, the stream is proxied through Invidious for you to then watch at a higher or automatic quality.

34
Home.md

@ -1,35 +1,3 @@
**Announcement:**
Due to the addition of multiples [Invidious instance violating the AGPL](https://github.com/iv-org/invidious/issues?q=is%3Aissue+label%3A%22agpl+violation%22). Editing the wiki is now restricted.
The wiki will soon be merged to the code repository.
In the meantime, if you have created a new public instance and wants it to be added feel free to open an issue, or contact one of the project manager.
---
## General
- [Public Invidious Instances](./Invidious-Instances)
- [Extensions](./Extensions)
- [Always proxy videos through server](./Always-use-"local"-to-proxy-video-through-the-server-without-creating-an-account)
- [Preferences](./Preferences)
- [Geoblocking, available quality and DASH](./Geoblocking,-available-video-quality-and-DASH)
- [Using search operators](./Search-operators)
- [List of URL parameters](./List-of-URL-parameters)
- [How to deal with uMatrix](./How-to-deal-with-uMatrix)
## For Administrators
- [Configuration](./Configuration)
- [Updating](./Updating)
- [Apache2 Virtual Host with Reverse Proxy](./Apache2-Reverse-Proxy)
- [Nginx Reverse Proxy Configuration](./NGINX-Reverse-Proxy)
- [Database Information and Maintenance](./Database-Information-and-Maintenance)
- [Issues with CAPTCHA](./Issues-with-CAPTCHA-on-Debian-and-Ubuntu)
- [How to setup Anti-Captcha](./How-to-setup-Anti-Captcha)
## For Developers
- [API](./API)
- [Authenticated Endpoints](./Authenticated-Endpoints)
Due to the addition of multiples [Invidious instance violating the AGPL](https://github.com/iv-org/invidious/issues?q=is%3Aissue+label%3A%22agpl+violation%22). The documentation has been moved to its own repository: https://github.com/iv-org/documentation

@ -1,5 +0,0 @@
If you're using [uMatrix](https://github.com/gorhill/uMatrix), you'll not be able to automatically play a video served by Invidious on other websites without unblocking requests to Invidious instances.
So, to make it work, you'll need to allow `css`, `image`, `media`, `script`, `xhr`, `frame` for the instance form which you're trying to play the video.
Since there are more and more Invidious instances, you can use the tool called [Invimatrix](https://booteille.gitlab.io/invimatrix/) to automatically generate uMatrix rules for every known instances.

@ -1,10 +0,0 @@
1. Register on anti-captcha.com: https://anti-captcha.com/clients/entrance/register and finish the registration with the link provided in your mailbox.
2. Head over the "Add fund" page: https://anti-captcha.com/clients/finance/refill and use whatever currency you prefer to use for adding $2 into your balance.
Do note that cryptocurrencies give a bonus of 20% at the first time you add funds then 10% for each new recharge.
3. After adding funds, go the API key link: https://anti-captcha.com/clients/settings/apisetup and copy your "Account key" (**never share it, it's confidential**).
4. Edit your Invidious `config.yml` file (should be located in the `config` directory) and add your account key at the end of the file after the `captcha_key` parameter.
Here is an example:
```yml
captcha_key: acuGae2riad5quashoug3Leeh
```
5. Restart Invidious and that's it!

@ -1,43 +0,0 @@
#### Warning: If you use ImageMagick on Ubuntu for other services like Mastodon this guide may break them, please use [this guide](https://linuxconfig.org/how-to-install-imagemagick-7-on-ubuntu-18-04-linux) instead.
There is some issue on Debian 9 and Ubuntu 18.04 and later. It appears that the clock (the CAPTCHA) has no hands but you can see them outside the clock. You need to compile ImageMagick yourself with librsvg to solve this issue.
Thanks [Tmiland](https://github.com/tmiland) for showing up a solution at [#299](https://github.com/iv-org/invidious/issues/299)
For lazy people a little hack is to disable CAPTCHA or use text one.
You can check if your version of ImageMagick is affected with `convert -list format`.
It should show the following if your installed version is okay.
```
SVG SVG rw+ Scalable Vector Graphics (RSVG 2.40.13)
SVGZ SVG rw+ Compressed Scalable Vector Graphics (RSVG 2.40.13)
```
If this is not the case your version is not compiled with librsvg, then you get the following.
```
SVG SVG rw+ Scalable Vector Graphics (XML 2.9.4)
SVGZ SVG rw+ Compressed Scalable Vector Graphics (XML 2.9.4)
```
Follow the steps to fix this issue:
`$ sudo apt purge imagemagick`
```bash
$ cd /tmp
# check for new releases: https://github.com/ImageMagick/ImageMagick6/releases
$ wget https://github.com/ImageMagick/ImageMagick6/archive/6.9.11-19.tar.gz
$ tar -xvf 6.9.10-24.tar.gz
$ cd ImageMagick6-6.9.10-24
$ ./configure --with-rsvg
$ make
$ sudo make install
```
Set the correct path: `$ sudo ln -s /usr/local/bin/convert /usr/bin/convert`
If you get an error here that this file already exists, please execute `$ sudo apt autoremove`
Now `convert -list format` reports
SVG rw+ Scalable Vector Graphics (RSVG 2.40.16)
SVGZ rw+ Compressed Scalable Vector Graphics (RSVG 2.40.16)
Restart Invidious, just to be sure `$ sudo systemctl restart invidious.service`

@ -1,6 +0,0 @@
In this wiki page some known exceptions from the logfile are listed. You normally do not have to worry if you see them.
#### Error reading socket: Connection reset by peer (Errno)
"Connection reset by peer" means the client disconnected before the site finished loading
#### Error writing to socket: Broken pipe (Errno)

@ -1,92 +0,0 @@
A list of URL parameters for Invidious, which can automatically toggle various UI and player settings.
_This list is incomplete. You can help by expanding it._
| Parameter | Setting |
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Site-wide parameters** | |
| _Dark mode_ | Configure default theme without setting cookies |
| `dark_mode=true` | Use dark theme |
| `dark_mode=false` | Use light theme |
| _Thin mode_ | Load HTML, CSS, JS and video elements (disables images) |
| `thin_mode=true` | Enabled |
| `thin_mode=false` | Disabled |
| _UI Language_ | Available locales are also listed [here](https://github.com/iv-org/invidious/blob/0.17.0/src/invidious.cr#L63-L75) |
| `hl=ar` | Arabic |
| `hl=de` | German |
| `hl=el` | Greek |
| `hl=en-US` | English |
| `hl=eo` | Esperanto |
| `hl=es` | Spanish |
| `hl=eu` | Basque |
| `hl=fr` | French |
| `hl=is` | Icelandic |
| `hl=it` | Italian |
| `hl=nb_NO` | Norwegian Bokmål |
| `hl=nl` | Dutch |
| `hl=pl` | Polish |
| `hl=ru` | Russian |
| `hl=uk` | Ukranian |
| `hl=zh-CN` | Chinese (traditional) |
| **Player parameters** | Available parameters also listed [here](https://github.com/iv-org/invidious/blob/0.17.0/src/invidious/videos.cr#L244) |
| _Annotations_ | Show legacy annotations, provided by the [Internet Archive](https://archive.org/details/youtubeannotations) |
| `iv_load_policy=1` | Show annotations |
| `iv_load_policy=3` | Hide annotations |
| _Autoplay_ | Automatically play video on load |
| `autoplay=1` | Enabled |
| `autoplay=0` | Disabled |
| _Continue_ | When video is done, automatically go to the next related video (similar to YouTubes _Autoplay_ feature) |
| `continue=1` | Enabled |
| `continue=0` | Disabled |
| _Listen_ | Play only audio portion of video |
| `listen=true` | Enabled |
| `listen=false` | Disabled |
| _Local_ | Proxy video streams, equivalent to enabling `Proxy videos?` in preferences |
| `local=true` | Enabled |
| `local=false` | Disabled |
| _Subtitles_ | List of ISO 639-1 language codes (comma-separated) |
| `subtitles=en` | English (will use `auto-generated` if native translation is unavailable) |
| _Quality_ | Default player quality |
| `quality=dash` | [DASH](https://en.wikipedia.org/wiki/Dynamic_Adaptive_Streaming_over_HTTP) |
| `quality=hd720` | 720p |
| `quality=medium` | 480p |
| _Related Videos_ | Show "Related videos" tab on the right-hand side |
| `related_videos=false` | Disabled |
| _Speed_ | Default player speed, can be any positive number |
| `speed=0.5` | Play at 0.5x speed |
| `speed=2` | Play at 2x speed |
| `speed=9.34` | Play at 9.34x speed |
| _Loop_ | Loop player by default |
| `loop=1` | Enabled |
| `loop=0` | Disabled |
| _Volume_ | Default player volume, can be any whole number between 0 and 100 |
| `volume=10` | Play video at 10% volume |
| _Region_ | Provide "hint" (as ISO 3166 country code) for Invidious to load videos from the specified region |
| `region=JP` | Attempt to load video as if the user were in Japan |
| `region=DE` | Attempt to load video as if the user were in Germany |
| _Controls_ | Provide player controls |
| `controls=1` | Enabled |
| `controls=0` | Disabled |
| _Raw_ | Redirect to latest copy of video at the specified `quality` and optionally proxy video |
| `raw=1` | Enabled |
| `raw=0` | Disabled |
| _Time controls_ | Control when the player starts and stops playback. Providing `loop=1` will only loop the specified section |
| `start=TIME`, `t=TIME`, `time_continue=TIME` | Start playback at `TIME` seconds into the video. Supports `TIME` as either an integer specifying seconds or using `12h30m10s22ms` syntax. For example, `t=12m9s` is equivalent to `t=729` |
| `end=TIME` | Stop playback at either `TIME` seconds or using the above mentioned `12h56m10s22ms` syntax. |
| **Search parameters** | |
| _Region_ | Provide "hint" (as ISO 3166 country code) for Invidious to load search results from the specified region |
| `region=JP` | Attempt to load search results as if the user were in Japan |
| `region=DE` | Attempt to load search results as if the user were in Germany |
| **Trending parameters** | |
| _Trending type_ | View trending videos only in a specific category |
| `type=Default` | Default |
| `type=Music` | Music |
| `type=Gaming` | Gaming |
| `type=News` | News |
| `type=Movies` | Movies |
| _Region_ | Provide "hint" (as ISO 3166 country code) for Invidious to load trending videos from the specified region | |
| `region=JP` | Load videos that are trending in Japan |
| `region=DE` | Load videos that are trending in Germany |
| **Player Style** | |
| `player_style=invidious` | Invidious, the default |
| `player_style=youtube` | YouTube, using a centered play button and always visible video control bar |

@ -1,28 +0,0 @@
This is a very basic config, secured with Let's Encrypt. Any log is disabled by default. Do not forget to replace `server_name` with your domain.
```
server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name invidious.domain.tld;
access_log off;
error_log /var/log/nginx/error.log crit;
ssl_certificate /etc/letsencrypt/live/invidious.domain.tld/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/invidious.domain.tld/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000/;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host; # so Invidious knows domain
proxy_http_version 1.1; # to keep alive
proxy_set_header Connection ""; # to keep alive
}
if ($https = '') { return 301 https://$host$request_uri; } # if not connected to HTTPS, perma-redirect to HTTPS
}
```

@ -1,44 +0,0 @@
Preferences for Invidious can be stored in a cookie named `PREFS`. This cookie can be set on the Invidious Preferences page.
If setting the cookie value yourself, the value must be in JSON format and then URL-encoded.
These are the preferences you can set:
```
{
"video_loop":true, // Always loop
"annotations":true, // Show annotations
"annotations_subscribed":true, // Show annotations for subscribed channels
"autoplay":true, // Autoplay current video
"continue":true, // Load next video when current video finishes
"continue_autoplay":true, // Load and autoplay next video
"listen":true, // Audio-only mode by default
"local": true, // Proxy requests via Invidious instance for privacy
"speed":1.0, // Also accepts '0.5', '1.5', '2.0'
"quality":"hd720", // Also accepts 'dash' for 1080p, 'medium', 'small'
"volume":100, // Default audio volume (0 = Min, 100 = Max)
"comments":[ // Source to use for comments; 'youtube' or 'reddit'
"youtube",
""
],
"captions":[ // Language captions in order of preference
"",
"",
""
],
"related_videos":true, // Show related videos
"redirect_feed":true, // Redirect homepage to subscription feed
"locale":"en-US", // Choose interface language
"dark_mode":true, // Use dark mode
"thin_mode":true, // Don't include pictures in page load
"player_style":"invidious", // Invidious style, the default
"player_style":"youtube", // YouTube style, using a centered play button and always visible video control bar
// For registered users (currently unused):
"max_results":40,
"sort":"published",
"latest_only":false,
"unseen_only":false,
"notifications_only":false
}
```

@ -1,47 +0,0 @@
Invidious supports the various search filters provided by YouTube.
Support for more user-friendly search is planned, see [#179](https://github.com/iv-org/invidious/issues/179).
Search filters are currently implemented as `key:value` operators, similar to [DuckDuckGo](https://help.duckduckgo.com/duckduckgo-help-pages/results/syntax/) and other search engines. Operators can be added to the search query to filter results, for example: [`type:playlist sort:views music`](https://invidio.us/search?q=type%3Aplaylist+sort%3Adate+music).
When using `subscriptions:true` or `channel:UCxxx` other filters are not applied.
Supported operators:
- `sort:`
- `relevance` (default)
- `rating`
- `upload_date`, `date`
- `view_count`, `views`
- `date:`
- `hour`
- `today`
- `week`
- `month`
- `year`
- `type:`
- `all` (default)
- `video`
- `channel`
- `playlist`
- `movie`
- `show`
- `duration:`
- `short`
- `long`
- `features:` Multiple can be specified, for example `features:live,4k,subtitles`
- `hd`
- `subtitles`
- `creative_commons`,`cc`
- `live`, `livestream`
- `purchased`
- `4k`
- `360`
- `location`
- `hdr`
- `channel:`, `user:`
- `UCxxxxxxxxxxxxxxxxxxxxxx`
- `author` Can be ambiguous, so using `UCID` is recommended
- `subscriptions:` If logged in, search only for videos from subscribed channels
- `true`
- `false`

@ -1,34 +0,0 @@
## Invidious releases are based on tags. You can use them if you want to be sure your instance is stable.
#### With release tags
```bash
$ sudo -i -u invidious
$ cd invidious
$ currentVersion=$(git rev-list --max-count=1 --abbrev-commit HEAD)
$ git pull
$ latestVersion=$(git describe --tags --abbrev=0)
$ git checkout $latestVersion
$ for i in `git rev-list --reverse --abbrev-commit $currentVersion..HEAD` ; do file=./config/migrate-scripts/migrate-db-$i.sh ; [ -f $file ] && $file ; done
$ shards update && shards install
$ crystal build src/invidious.cr --release
$ exit
$ sudo systemctl restart invidious.service
```
#### With master branch
```bash
$ sudo -i -u invidious
$ cd invidious
$ currentVersion=$(git rev-list --max-count=1 --abbrev-commit HEAD)
$ git pull
$ for i in `git rev-list --reverse --abbrev-commit $currentVersion..HEAD` ; do file=./config/migrate-scripts/migrate-db-$i.sh ; [ -f $file ] && $file ; done
$ shards update && shards install
$ crystal build src/invidious.cr --release
$ exit
$ sudo systemctl restart invidious.service
```
#### With Docker:
```bash
$ docker-compose pull && docker-compose up --force-recreate --build && docker image prune -f
```