Compare commits

..

1 Commits

Author SHA1 Message Date
50bab26a3a Add support for CONNECT proxy 2020-05-25 18:52:36 -05:00
306 changed files with 16110 additions and 34277 deletions

View File

@ -1,88 +0,0 @@
#
# Lint
#
# Exclude assigns for ECR files
Lint/UselessAssign:
Excluded:
- src/invidious.cr
- src/invidious/helpers/errors.cr
- src/invidious/routes/**/*.cr
# Ignore false negative (if !db.query_one?...)
Lint/UnreachableCode:
Excluded:
- src/invidious/database/base.cr
# Ignore shadowed variable `key` (it works for now, and that's
# a sensitive part of the code)
Lint/ShadowingOuterLocalVar:
Excluded:
- src/invidious/helpers/tokens.cr
#
# Style
#
Style/RedundantBegin:
Enabled: false
Style/RedundantReturn:
Enabled: false
#
# Metrics
#
# Ignore function complexity (number of if/else & case/when branches)
# For some functions that can hardly be simplified for now
Metrics/CyclomaticComplexity:
Excluded:
# get_about_info(ucid, locale) => [17/10]
- src/invidious/channels/about.cr
# fetch_channel_community(ucid, continuation, ...) => [34/10]
- src/invidious/channels/community.cr
# create_notification_stream(env, topics, connection_channel) => [14/10]
- src/invidious/helpers/helpers.cr:84:5
# get_index(plural_form, count) => [25/10]
- src/invidious/helpers/i18next.cr
# call(context) => [18/10]
- src/invidious/helpers/static_file_handler.cr
# show(env) => [38/10]
- src/invidious/routes/embed.cr
# get_video_playback(env) => [45/10]
- src/invidious/routes/video_playback.cr
# handle(env) => [40/10]
- src/invidious/routes/watch.cr
# playlist_ajax(env) => [24/10]
- src/invidious/routes/playlists.cr
# fetch_youtube_comments(id, cursor, ....) => [40/10]
# template_youtube_comments(comments, locale, ...) => [16/10]
# content_to_comment_html(content) => [14/10]
- src/invidious/comments.cr
# to_json(locale, json) => [21/10]
# extract_video_info(video_id, ...) => [44/10]
# process_video_params(query, preferences) => [20/10]
- src/invidious/videos.cr
#src/invidious/playlists.cr:327:5
#[C] Metrics/CyclomaticComplexity: Cyclomatic complexity too high [19/10]
# fetch_playlist(plid : String)
#src/invidious/playlists.cr:436:5
#[C] Metrics/CyclomaticComplexity: Cyclomatic complexity too high [11/10]
# extract_playlist_videos(initial_data : Hash(String, JSON::Any))

3
.gitattributes vendored
View File

@ -1,3 +0,0 @@
# https://github.community/t/how-to-change-the-category/2261/3
videojs-*.js linguist-detectable=false
video.min.js linguist-detectable=false

18
.github/CODEOWNERS vendored
View File

@ -1,18 +0,0 @@
# 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
README.md @thefrenchghosty
config/config.example.yml @thefrenchghosty @SamantazFox @unixfox
scripts/ @syeopite
shards.lock @syeopite
shards.yml @syeopite
locales/ @SamantazFox
src/invidious/helpers/i18n.cr @SamantazFox
src/invidious/helpers/youtube_api.cr @SamantazFox

1
.github/FUNDING.yml vendored
View File

@ -1 +0,0 @@
custom: https://invidious.io/donate/

View File

@ -1,42 +0,0 @@
---
name: Bug report
about: Create a bug report to help us improve Invidious
title: '[Bug] '
labels: bug
assignees: ''
---
<!--
BEFORE TRYING TO REPORT A BUG:
* Read the FAQ!
* Use the search function to check if there is already an issue open for your problem!
If you want to suggest a new feature please use "Feature request" instead
If you want to suggest an enhancement to an existing feature please use "Enhancement" instead
-->
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
**Steps to Reproduce**
<!-- Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
-->
**Logs**
<!-- If applicable, copy the log that appear in the browser page where the error is reported. -->
**Screenshots**
<!-- If applicable, add screenshots to help explain your problem. -->
**Additional context**
<!-- Add any other context about the problem here.
- Browser (if applicable):
- OS (if applicable):
-->

View File

@ -1,24 +0,0 @@
---
name: Enhancement
about: Suggest an enhancement for an existing feature
title: '[Enhancement] '
labels: enhancement
assignees: ''
---
<!-- Please use the search function to check if the desired function has already been requested by someone else -->
<!-- If you want to suggest a new feature please use "Feature request" instead -->
<!-- If you want to report a bug, please use "Bug report" instead -->
**Is your enhancement request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
**Describe the solution you'd like**
<!-- A clear and concise description of what you want to happen. -->
**Describe alternatives you've considered**
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
**Additional context**
<!-- Add any other context or screenshots about the enhancement here. -->

View File

@ -1,24 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: '[Feature request] '
labels: feature-request
assignees: ''
---
<!-- Please use the search function to check if the desired function has already been requested by someone else -->
<!-- If you want to suggest an enhancement to an existing feature please use "Enhancement" instead -->
<!-- If you want to report a bug, please use "Bug report" instead -->
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
**Describe the solution you'd like**
<!-- A clear and concise description of what you want to happen. -->
**Describe alternatives you've considered**
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
**Additional context**
<!-- Add any other context or screenshots about the feature request here. -->

View File

@ -1,127 +0,0 @@
name: Invidious CI
on:
schedule:
- cron: "0 0 * * *" # Every day at 00:00
push:
branches:
- "master"
- "api-only"
pull_request:
branches: "*"
paths-ignore:
- "*.md"
- LICENCE
- TRANSLATION
- invidious.service
- .git*
- .editorconfig
- screenshots/*
- assets/**
- locales/*
- config/**
- .github/ISSUE_TEMPLATE/*
- kubernetes/**
jobs:
build:
runs-on: ubuntu-latest
name: "build - crystal: ${{ matrix.crystal }}, stable: ${{ matrix.stable }}"
continue-on-error: ${{ !matrix.stable }}
strategy:
fail-fast: false
matrix:
stable: [true]
crystal:
- 1.2.2
- 1.3.2
- 1.4.0
- 1.5.0
include:
- crystal: nightly
stable: false
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Install Crystal
uses: crystal-lang/install-crystal@v1.6.0
with:
crystal: ${{ matrix.crystal }}
- name: Cache Shards
uses: actions/cache@v3
with:
path: ./lib
key: shards-${{ hashFiles('shard.lock') }}
- name: Install Shards
run: |
if ! shards check; then
shards install
fi
- name: Run tests
run: crystal spec
- name: Run lint
run: |
if ! crystal tool format --check; then
crystal tool format
git diff
exit 1
fi
- name: Build
run: crystal build --warnings all --error-on-warnings --error-trace src/invidious.cr
build-docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker
run: docker-compose build --build-arg release=0
- name: Run Docker
run: docker-compose up -d
- name: Test Docker
run: while curl -Isf http://localhost:3000; do sleep 1; done
build-docker-arm64:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: arm64
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build Docker ARM64 image
uses: docker/build-push-action@v3
with:
context: .
file: docker/Dockerfile.arm64
platforms: linux/arm64/v8
build-args: release=0
- name: Test Docker
run: while curl -Isf http://localhost:3000; do sleep 1; done

View File

@ -1,77 +0,0 @@
name: Build and release container
on:
push:
branches:
- "master"
paths-ignore:
- "*.md"
- LICENCE
- TRANSLATION
- invidious.service
- .git*
- .editorconfig
- screenshots/*
- .github/ISSUE_TEMPLATE/*
- kubernetes/**
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Crystal
uses: crystal-lang/install-crystal@v1.6.0
with:
crystal: 1.5.0
- name: Run lint
run: |
if ! crystal tool format --check; then
crystal tool format
git diff
exit 1
fi
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: arm64
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to registry
uses: docker/login-action@v2
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_PASSWORD }}
- name: Build and push Docker AMD64 image for Push Event
if: github.ref == 'refs/heads/master'
uses: docker/build-push-action@v3
with:
context: .
file: docker/Dockerfile
platforms: linux/amd64
labels: quay.expires-after=12w
push: true
tags: quay.io/invidious/invidious:${{ github.sha }},quay.io/invidious/invidious:latest
build-args: release=1
- name: Build and push Docker ARM64 image for Push Event
if: github.ref == 'refs/heads/master'
uses: docker/build-push-action@v3
with:
context: .
file: docker/Dockerfile.arm64
platforms: linux/arm64/v8
labels: quay.expires-after=12w
push: true
tags: quay.io/invidious/invidious:${{ github.sha }}-arm64,quay.io/invidious/invidious:latest-arm64
build-args: release=1

View File

@ -1,24 +0,0 @@
# Documentation: https://github.com/marketplace/actions/close-stale-issues
name: "Stale issue handler"
on:
workflow_dispatch:
schedule:
- cron: "0 */12 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 365
days-before-pr-stale: 45 # PRs should be active. Anything that hasn't had activity in more than 45 days should be considered abandoned.
days-before-close: 30
exempt-pr-labels: blocked
stale-issue-message: 'This issue has been automatically marked as stale and will be closed in 30 days because it has not had recent activity and is much likely outdated. If you think this issue is still relevant and applicable, you just have to post a comment and it will be unmarked.'
stale-pr-message: 'This pull request has been automatically marked as stale and will be closed in 30 days because it has not had recent activity and is much likely abandoned or outdated. If you think this pull request is still relevant and applicable, you just have to post a comment and it will be unmarked.'
stale-issue-label: "stale"
stale-pr-label: "stale"
ascending: true

2
.gitignore vendored
View File

@ -6,4 +6,4 @@
/.vscode/
/invidious
/sentry
/config/config.yml
shard.lock

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "mocks"]
path = mocks
url = ../mocks

31
.travis.yml Normal file
View File

@ -0,0 +1,31 @@
dist: bionic
jobs:
include:
- stage: build
# TODO: Shallowly clone again once the .git folder is no longer required for building
git:
depth: false
language: crystal
crystal: latest
before_install:
- shards update
- shards install
install:
- crystal build --warnings all --error-on-warnings src/invidious.cr
script:
- crystal tool format --check
- crystal spec
- stage: build_docker
# TODO: Shallowly clone again once the .git folder is no longer required for building
git:
depth: false
language: minimal
services:
- docker
install:
- docker-compose build
script:
- docker-compose up -d
- while curl -Isf http://localhost:3000; do sleep 1; done

View File

@ -1,5 +1,3 @@
# Note: This is no longer updated and links to omarroths repo, which doesn't exist anymore.
# 0.20.0 (2019-011-06)
# Version 0.20.0: Custom Playlists
@ -402,7 +400,7 @@ An `/api/v1/stats` endpoint has been added with [#356](https://github.com/omarro
## For Developers
`/api/v1/channels/:ucid` now provides an `autoGenerated` tag, which returns true for topic channels, and larger genre channels generated by YouTube. These channels don't have any videos of their own, so `latestVideos` will be empty. It is recommended instead to display a list of playlists generated by YouTube.
`/api/v1/channels/:ucid` now provides an `autoGenerated` tag, which returns true for [topic channels](https://www.youtube.com/channel/UCE80FOXpJydkkMo-BYoJdEg), and larger [genre channels](https://www.youtube.com/channel/UC-9-kyTW8ZkZNDHQJ6FgpwQ) generated by YouTube. These channels don't have any videos of their own, so `latestVideos` will be empty. It is recommended instead to display a list of playlists generated by YouTube.
You can now pull a list of playlists from a channel with `/api/v1/channels/playlists/:ucid`. Supported options are documented in the [wiki](https://github.com/omarroth/invidious/wiki/API#get-apiv1channelsplaylistsucid-apiv1channelsucidplaylists). Pagination is handled with a `continuation` token, which is generated on each call. Of note is that auto-generated channels currently have one page of results, and subsequent calls will be empty.

119
Makefile
View File

@ -1,119 +0,0 @@
# -----------------------
# Compilation options
# -----------------------
RELEASE := 1
STATIC := 0
DISABLE_QUIC := 0
NO_DBG_SYMBOLS := 0
FLAGS ?=
ifeq ($(RELEASE), 1)
FLAGS += --release
endif
ifeq ($(STATIC), 1)
FLAGS += --static
endif
ifeq ($(NO_DBG_SYMBOLS), 1)
FLAGS += --no-debug
else
FLAGS += --debug
endif
ifeq ($(DISABLE_QUIC), 1)
FLAGS += -Ddisable_quic
endif
# -----------------------
# Main
# -----------------------
all: invidious
get-libs:
shards install --production
# TODO: add support for ARM64 via cross-compilation
invidious: get-libs
crystal build src/invidious.cr $(FLAGS) --progress --stats --error-trace
run: invidious
./invidious
# -----------------------
# Development
# -----------------------
format:
crystal tool format
test:
crystal spec
verify:
crystal build src/invidious.cr -Dskip_videojs_download \
--no-codegen --progress --stats --error-trace
# -----------------------
# (Un)Install
# -----------------------
# TODO
# -----------------------
# Cleaning
# -----------------------
clean:
rm invidious
distclean: clean
rm -rf libs
# -----------------------
# Help page
# -----------------------
help:
@echo "Targets available in this Makefile:"
@echo ""
@echo " get-libs Fetch Crystal libraries"
@echo " invidious Build Invidious"
@echo " run Launch Invidious"
@echo ""
@echo " format Run the Crystal formatter"
@echo " test Run tests"
@echo " verify Just make sure that the code compiles, but without"
@echo " generating any binaries. Useful to search for errors"
@echo ""
@echo " clean Remove build artifacts"
@echo " distclean Remove build artifacts and libraries"
@echo ""
@echo ""
@echo "Build options available for this Makefile:"
@echo ""
@echo " RELEASE Make a release build (Default: 1)"
@echo " STATIC Link libraries statically (Default: 0)"
@echo ""
@echo " DISABLE_QUIC Disable support for QUIC (Default: 0)"
@echo " NO_DBG_SYMBOLS Strip debug symbols (Default: 0)"
# No targets generates an output named after themselves
.PHONY: all get-libs build amd64 run
.PHONY: format test verify clean distclean help

362
README.md
View File

@ -1,179 +1,255 @@
<div align="center">
<img src="assets/invidious-colored-vector.svg" width="192" height="192" alt="Invidious logo">
<h1>Invidious</h1>
# Invidious
<a href="https://www.gnu.org/licenses/agpl-3.0.en.html">
<img alt="License: AGPLv3" src="https://shields.io/badge/License-AGPL%20v3-blue.svg">
</a>
<a href="https://github.com/iv-org/invidious/actions">
<img alt="Build Status" src="https://github.com/iv-org/invidious/workflows/Invidious%20CI/badge.svg">
</a>
<a href="https://github.com/iv-org/invidious/commits/master">
<img alt="GitHub commits" src="https://img.shields.io/github/commit-activity/y/iv-org/invidious?color=red&label=commits">
</a>
<a href="https://github.com/iv-org/invidious/issues">
<img alt="GitHub issues" src="https://img.shields.io/github/issues/iv-org/invidious?color=important">
</a>
<a href="https://github.com/iv-org/invidious/pulls">
<img alt="GitHub pull requests" src="https://img.shields.io/github/issues-pr/iv-org/invidious?color=blueviolet">
</a>
<a href="https://hosted.weblate.org/engage/invidious/">
<img alt="Translation Status" src="https://hosted.weblate.org/widgets/invidious/-/translations/svg-badge.svg">
</a>
[![Build Status](https://travis-ci.org/omarroth/invidious.svg?branch=master)](https://travis-ci.org/omarroth/invidious)
<a href="https://github.com/humanetech-community/awesome-humane-tech">
<img alt="Awesome Humane Tech" src="https://raw.githubusercontent.com/humanetech-community/awesome-humane-tech/main/humane-tech-badge.svg?sanitize=true">
</a>
## Invidious is an alternative front-end to YouTube
<h3>An open source alternative front-end to YouTube</h3>
- Audio-only mode (and no need to keep window open on mobile)
- [Free software](https://github.com/omarroth/invidious) (AGPLv3 licensed)
- No ads
- No need to create a Google account to save subscriptions
- Lightweight (homepage is ~4 KB compressed)
- Tools for managing subscriptions:
- Only show unseen videos
- Only show latest (or latest unseen) video from each channel
- Delivers notifications from all subscribed channels
- Automatically redirect homepage to feed
- Import subscriptions from YouTube
- Dark mode
- Embed support
- Set default player options (speed, quality, autoplay, loop)
- Does not require JS to play videos
- Support for Reddit comments in place of YT comments
- Import/Export subscriptions, watch history, preferences
- Does not use any of the official YouTube APIs
- Developer [API](https://github.com/omarroth/invidious/wiki/API)
<a href="https://invidious.io/">Website</a>
&nbsp;&nbsp;
<a href="https://instances.invidious.io/">Instances list</a>
&nbsp;&nbsp;
<a href="https://docs.invidious.io/faq/">FAQ</a>
&nbsp;&nbsp;
<a href="https://docs.invidious.io/">Documentation</a>
&nbsp;&nbsp;
<a href="#contribute">Contribute</a>
&nbsp;&nbsp;
<a href="https://invidious.io/donate/">Donate</a>
Liberapay: https://liberapay.com/omarroth
BTC: 356DpZyMXu6rYd55Yqzjs29n79kGKWcYrY
BCH: qq4ptclkzej5eza6a50et5ggc58hxsq5aylqut2npk
<h5>Chat with us:</h5>
<a href="https://matrix.to/#/#invidious:matrix.org">
<img alt="Matrix" src="https://img.shields.io/matrix/invidious:matrix.org?label=Matrix&color=darkgreen">
</a>
<a href="https://web.libera.chat/?channel=#invidious">
<img alt="Libera.chat (IRC)" src="https://img.shields.io/badge/IRC%20%28Libera.chat%29-%23invidious-darkgreen">
</a>
<br>
<a rel="me" href="https://social.tchncs.de/@invidious">
<img alt="Fediverse: @invidious@social.tchncs.de" src="https://img.shields.io/badge/Fediverse-%40invidious%40social.tchncs.de-darkgreen">
</a>
<br>
<a href="https://invidious.io/contact/">
<img alt="E-mail" src="https://img.shields.io/badge/E%2d%2dmail-darkgreen">
</a>
</div>
## Invidious Instances
See [Invidious Instances](https://github.com/omarroth/invidious/wiki/Invidious-Instances) for a full list of publicly available instances.
### Official Instances
- [invidio.us](https://invidio.us) 🇺🇸
Issuer: Let's Encrypt, [SSLLabs Verification](https://www.ssllabs.com/ssltest/analyze.html?d=invidio.us)
- [kgg2m7yk5aybusll.onion](http://kgg2m7yk5aybusll.onion)
- [axqzx4s6s54s32yentfqojs3x5i7faxza6xo3ehd4bzzsg2ii4fv2iid.onion](http://axqzx4s6s54s32yentfqojs3x5i7faxza6xo3ehd4bzzsg2ii4fv2iid.onion)
## Screenshots
| Player | Preferences | Subscriptions |
|-------------------------------------|-------------------------------------|---------------------------------------|
| ![](screenshots/01_player.png) | ![](screenshots/02_preferences.png) | ![](screenshots/03_subscriptions.png) |
| ![](screenshots/04_description.png) | ![](screenshots/05_preferences.png) | ![](screenshots/06_subscriptions.png) |
| Player | Preferences | Subscriptions |
| ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| [<img src="screenshots/01_player.png?raw=true" height="140" width="280">](screenshots/01_player.png?raw=true) | [<img src="screenshots/02_preferences.png?raw=true" height="140" width="280">](screenshots/02_preferences.png?raw=true) | [<img src="screenshots/03_subscriptions.png?raw=true" height="140" width="280">](screenshots/03_subscriptions.png?raw=true) |
| [<img src="screenshots/04_description.png?raw=true" height="140" width="280">](screenshots/04_description.png?raw=true) | [<img src="screenshots/05_preferences.png?raw=true" height="140" width="280">](screenshots/05_preferences.png?raw=true) | [<img src="screenshots/06_subscriptions.png?raw=true" height="140" width="280">](screenshots/06_subscriptions.png?raw=true) |
## Installation
## Features
See [Invidious-Updater](https://github.com/tmiland/Invidious-Updater) for a self-contained script that can automatically install and update Invidious.
**User features**
- Lightweight
- No ads
- No tracking
- No JavaScript required
- Light/Dark themes
- Customizable homepage
- Subscriptions independent from Google
- Notifications for all subscribed channels
- Audio-only mode (with background play on mobile)
- Support for Reddit comments
- [Available in many languages](locales/), thanks to [our translators](#contribute)
### Docker:
**Data import/export**
- Import subscriptions from YouTube, NewPipe and Freetube
- Import watch history from NewPipe
- Export subscriptions to NewPipe and Freetube
- Import/Export Invidious user data
#### Build and start cluster:
**Technical features**
- Embedded video support
- [Developer API](https://docs.invidious.io/api/)
- Does not use official YouTube APIs
- No Contributor License Agreement (CLA)
```bash
$ docker-compose up
```
And visit `localhost:3000` in your browser.
## Quick start
#### Rebuild cluster:
**Using invidious:**
```bash
$ docker-compose build
```
- [Select a public instance from the list](https://instances.invidious.io) and start watching videos right now!
#### Delete data and rebuild:
**Hosting invidious:**
```bash
$ docker volume rm invidious_postgresdata
$ docker-compose build
```
- [Follow the installation instructions](https://docs.invidious.io/installation/)
### Linux:
#### Install dependencies
```bash
# Arch Linux
$ sudo pacman -S base-devel shards crystal librsvg postgresql
# Ubuntu or Debian
# First you have to add the repository to your APT configuration. For easy setup just run in your command line:
$ curl -sSL https://dist.crystal-lang.org/apt/setup.sh | sudo bash
# That will add the signing key and the repository configuration. If you prefer to do it manually, execute the following commands:
$ curl -sL "https://keybase.io/crystal/pgp_keys.asc" | sudo apt-key add -
$ echo "deb https://dist.crystal-lang.org/apt crystal main" | sudo tee /etc/apt/sources.list.d/crystal.list
$ sudo apt-get update
$ sudo apt install crystal libssl-dev libxml2-dev libyaml-dev libgmp-dev libreadline-dev postgresql librsvg2-bin libsqlite3-dev
```
#### Add invidious user and clone repository
```bash
$ useradd -m invidious
$ sudo -i -u invidious
$ git clone https://github.com/omarroth/invidious
$ exit
```
#### Setup PostgresSQL
```bash
$ sudo systemctl enable postgresql
$ sudo systemctl start postgresql
$ sudo -i -u postgres
$ psql -c "CREATE USER kemal WITH PASSWORD 'kemal';" # Change 'kemal' here to a stronger password, and update `password` in config/config.yml
$ createdb -O kemal invidious
$ psql invidious kemal < /home/invidious/invidious/config/sql/channels.sql
$ psql invidious kemal < /home/invidious/invidious/config/sql/videos.sql
$ psql invidious kemal < /home/invidious/invidious/config/sql/channel_videos.sql
$ psql invidious kemal < /home/invidious/invidious/config/sql/users.sql
$ psql invidious kemal < /home/invidious/invidious/config/sql/session_ids.sql
$ psql invidious kemal < /home/invidious/invidious/config/sql/nonces.sql
$ psql invidious kemal < /home/invidious/invidious/config/sql/annotations.sql
$ psql invidious kemal < /home/invidious/invidious/config/sql/playlists.sql
$ psql invidious kemal < /home/invidious/invidious/config/sql/playlist_videos.sql
$ exit
```
#### Setup Invidious
```bash
$ sudo -i -u invidious
$ cd invidious
$ shards update && shards install
$ crystal build src/invidious.cr --release
# test compiled binary
$ ./invidious # stop with ctrl c
$ exit
```
#### systemd service
```bash
$ sudo cp /home/invidious/invidious/invidious.service /etc/systemd/system/invidious.service
$ sudo systemctl enable invidious.service
$ sudo systemctl start invidious.service
```
#### Logrotate
```bash
$ sudo echo "/home/invidious/invidious/invidious.log {
rotate 4
weekly
notifempty
missingok
compress
minsize 1048576
}" | tee /etc/logrotate.d/invidious.logrotate
$ sudo chmod 0644 /etc/logrotate.d/invidious.logrotate
```
### OSX:
```bash
# Install dependencies
$ brew update
$ brew install shards crystal postgres imagemagick librsvg
# Clone repository and setup postgres database
$ git clone https://github.com/omarroth/invidious
$ cd invidious
$ brew services start postgresql
$ psql -c "CREATE ROLE kemal WITH PASSWORD 'kemal';" # Change 'kemal' here to a stronger password, and update `password` in config/config.yml
$ createdb -O kemal invidious
$ psql invidious kemal < config/sql/channels.sql
$ psql invidious kemal < config/sql/videos.sql
$ psql invidious kemal < config/sql/channel_videos.sql
$ psql invidious kemal < config/sql/users.sql
$ psql invidious kemal < config/sql/session_ids.sql
$ psql invidious kemal < config/sql/nonces.sql
$ psql invidious kemal < config/sql/annotations.sql
$ psql invidious kemal < config/sql/privacy.sql
$ psql invidious kemal < config/sql/playlists.sql
$ psql invidious kemal < config/sql/playlist_videos.sql
# Setup Invidious
$ shards update && shards install
$ crystal build src/invidious.cr --release
```
## Update Invidious
You can see how to update Invidious [here](https://github.com/omarroth/invidious/wiki/Updating).
## Usage:
```bash
$ ./invidious -h
Usage: invidious [arguments]
-b HOST, --bind HOST Host to bind (defaults to 0.0.0.0)
-p PORT, --port PORT Port to listen for connections (defaults to 3000)
-s, --ssl Enables SSL
--ssl-key-file FILE SSL key file
--ssl-cert-file FILE SSL certificate file
-h, --help Shows this help
-c THREADS, --channel-threads=THREADS
Number of threads for refreshing channels (default: 1)
-f THREADS, --feed-threads=THREADS
Number of threads for refreshing feeds (default: 1)
-o OUTPUT, --output=OUTPUT Redirect output (default: STDOUT)
-v, --version Print version
```
Or for development:
```bash
$ curl -fsSLo- https://raw.githubusercontent.com/samueleaton/sentry/master/install.cr | crystal eval
$ ./sentry
🤖 Your SentryBot is vigilant. beep-boop...
```
## Documentation
The full documentation can be accessed online at https://docs.invidious.io/
[Documentation](https://github.com/omarroth/invidious/wiki) can be found in the wiki.
The documentation's source code is available in this repository:
https://github.com/iv-org/documentation
## Extensions
### Extensions
[Extensions](https://github.com/omarroth/invidious/wiki/Extensions) can be found in the wiki, as well as documentation for integrating it into other projects.
We highly recommend the use of [Privacy Redirect](https://github.com/SimonBrazell/privacy-redirect#get),
a browser extension that automatically redirects Youtube URLs to any Invidious instance and replaces
embedded youtube videos on other websites with invidious.
## Made with Invidious
The documentation contains a list of browser extensions that we recommended to use along with Invidious.
- [FreeTube](https://github.com/FreeTubeApp/FreeTube): An Open Source YouTube app for privacy.
- [CloudTube](https://cadence.moe/cloudtube/subscriptions): A JS-rich alternate YouTube player
- [PeerTubeify](https://gitlab.com/Ealhad/peertubeify): On YouTube, displays a link to the same video on PeerTube, if it exists.
- [MusicPiped](https://github.com/deep-gaurav/MusicPiped): A materialistic music player that streams music from YouTube.
- [LapisTube](https://github.com/blubbll/lapis-tube): A fancy and advanced (experimental) YouTube frontend. Combined streams & custom YT features.
You can read more here: https://docs.invidious.io/applications/
## Contributing
1. Fork it ( https://github.com/omarroth/invidious/fork )
2. Create your feature branch (git checkout -b my-new-feature)
3. Commit your changes (git commit -am 'Add some feature')
4. Push to the branch (git push origin my-new-feature)
5. Create a new Pull Request
## Contribute
## Contact
### Code
Feel free to send an email to omarroth@protonmail.com or join our [Matrix Server](https://riot.im/app/#/room/#invidious:matrix.org), or #invidious on Freenode.
1. Fork it ( https://github.com/iv-org/invidious/fork ).
1. Create your feature branch (`git checkout -b my-new-feature`).
1. Stage your files (`git add .`).
1. Commit your changes (`git commit -am 'Add some feature'`).
1. Push to the branch (`git push origin my-new-feature`).
1. Create a new pull request ( https://github.com/iv-org/invidious/compare ).
You can also view release notes on the [releases](https://github.com/omarroth/invidious/releases) page or in the CHANGELOG.md included in the repository.
### Translations
## License
We use [Weblate](https://weblate.org) to manage Invidious translations.
[![GNU AGPLv3 Image](https://www.gnu.org/graphics/agplv3-155x51.png)](http://www.gnu.org/licenses/agpl-3.0.en.html)
You can suggest new translations and/or correction here: https://hosted.weblate.org/engage/invidious/.
Creating an account is not required, but recommended, especially if you want to contribute regularly.
Weblate also allows you to log-in with major SSO providers like Github, Gitlab, BitBucket, Google, ...
## Projects using Invidious
- [FreeTube](https://github.com/FreeTubeApp/FreeTube): A libre software YouTube app for privacy.
- [CloudTube](https://sr.ht/~cadence/tube/): A JavaScript-rich alternate YouTube player.
- [PeerTubeify](https://gitlab.com/Cha_deL/peertubeify): On YouTube, displays a link to the same video on PeerTube, if it exists.
- [MusicPiped](https://github.com/deep-gaurav/MusicPiped): A material design music player that streams music from YouTube.
- [HoloPlay](https://github.com/stephane-r/HoloPlay): Funny Android application connecting on Invidious API's with search, playlists and favorites.
- [WatchTube](https://github.com/WatchTubeTeam/WatchTube): Powerful YouTube client for Apple Watch.
- [Yattee](https://github.com/yattee/yattee): Alternative YouTube frontend for iPhone, iPad, Mac and Apple TV.
- [TubiTui](https://codeberg.org/777/TubiTui): A lightweight, libre, TUI-based YouTube client.
- [Ytfzf](https://github.com/pystardust/ytfzf): A posix script to find and watch youtube videos from the terminal. (Without API)
## Liability
We take no responsibility for the use of our tool, or external instances
provided by third parties. We strongly recommend you abide by the valid
official regulations in your country. Furthermore, we refuse liability
for any inappropriate use of Invidious, such as illegal downloading.
This tool is provided to you in the spirit of free, open software.
You may view the LICENSE in which this software is provided to you [here](./LICENSE).
> 16. Limitation of Liability.
>
> IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
Invidious is Free Software: You can use, study share and improve it at your
will. Specifically you can redistribute and/or modify it under the terms of the
[GNU Affero General Public License](https://www.gnu.org/licenses/agpl.html) as
published by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

View File

@ -1 +0,0 @@
https://hosted.weblate.org/projects/invidious/

37
assets/css/darktheme.css Normal file
View File

@ -0,0 +1,37 @@
a:hover,
a:active {
color: rgb(0, 182, 240);
}
a {
color: #a0a0a0;
text-decoration: none;
}
body {
background-color: rgba(35, 35, 35, 1);
color: #f0f0f0;
}
.pure-form legend {
color: #f0f0f0;
}
.pure-menu-heading {
color: #f0f0f0;
}
input,
select,
textarea {
color: rgba(35, 35, 35, 1);
}
.pure-form input[type="file"] {
color: #f0f0f0;
}
.navbar > .searchbar input {
background-color: inherit;
color: inherit;
}

View File

@ -5,26 +5,14 @@ body {
Arial, sans-serif;
}
#contents {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.deleted {
background-color: rgb(255, 0, 0, 0.5);
}
.underlined {
border-bottom: 1px solid;
margin-bottom: 20px;
}
.channel-profile > * {
font-size: 1.17em;
font-weight: bold;
vertical-align: middle;
border-radius: 50%;
}
.channel-profile > img {
@ -32,7 +20,7 @@ body {
height: auto;
}
body a.channel-owner {
.channel-owner {
background-color: #008bec;
color: #fff;
border-radius: 9px;
@ -72,22 +60,6 @@ body a.channel-owner {
color: rgb(255, 0, 0);
}
.feed-menu {
display: flex;
justify-content: center;
flex-wrap: wrap;
}
.feed-menu-item {
text-align: center;
}
@media screen and (max-width: 640px) {
.feed-menu-item {
flex: 0 0 40%;
}
}
.h-box {
padding-left: 1em;
padding-right: 1em;
@ -113,19 +85,15 @@ div {
padding-right: 10px;
}
body a.pure-button {
color: rgba(0,0,0,.8);
}
button.pure-button-primary,
body a.pure-button-primary,
a.pure-button-primary,
.channel-owner:hover {
background-color: #a0a0a0;
color: rgba(35, 35, 35, 1);
}
button.pure-button-primary:hover,
body a.pure-button-primary:hover {
a.pure-button-primary:hover {
background-color: rgba(0, 182, 240, 1);
color: #fff;
}
@ -184,7 +152,7 @@ img.thumbnail {
flex: 1;
}
.searchbar {
.navbar > .searchbar {
flex-grow: 2; /* take double the space of the other items */
}
@ -197,26 +165,20 @@ img.thumbnail {
display: inline;
}
.searchbar .pure-form fieldset { padding: 0; }
.navbar > .searchbar .pure-form input[type="search"] {
margin-bottom: 1px;
.searchbar input[type="search"] {
width: 100%;
margin: 1px;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid #ccc;
border-radius: 0;
border: 1px solid;
border-color: rgba(0,0,0,0);
border-bottom-color: #CCC;
border-radius: 0;
padding: initial 0;
box-shadow: none;
-webkit-appearance: none;
}
box-shadow: none;
.searchbar input[type="search"]:focus {
margin: 0 0 0.5px 0;
border: 2px solid;
border-color: rgba(0,0,0,0);
border-bottom-color: #FED;
-webkit-appearance: none;
}
/* https://stackoverflow.com/a/55170420 */
@ -228,6 +190,16 @@ input[type="search"]::-webkit-search-cancel-button {
background-size: 14px;
}
.navbar > .searchbar .pure-form fieldset {
padding: 0;
}
/* attract focus to the searchbar by adding a subtle transition */
.navbar > .searchbar .pure-form input[type="search"]:focus {
margin-bottom: 0px;
border-bottom: 2px solid #aaa;
}
.user-field {
display: flex;
flex-direction: row;
@ -236,7 +208,7 @@ input[type="search"]::-webkit-search-cancel-button {
}
.user-field div {
width: auto;
width: initial;
}
.user-field div:not(:last-child) {
@ -284,43 +256,21 @@ input[type="search"]::-webkit-search-cancel-button {
}
}
/*
* Video "cards" (results/playlist/channel videos)
*/
.video-card-row { margin: 15px 0; }
.flexible { display: flex; }
.flex-left { flex: 1 1 100%; flex-wrap: wrap; }
.flex-right { flex: 1 0 auto; flex-wrap: nowrap; }
p.channel-name { margin: 0; }
p.video-data { margin: 0; font-weight: bold; font-size: 80%; }
/*
* Footer
*/
footer {
color: #919191;
margin-top: auto;
padding: 1.5em 0;
.footer {
color: #666666;
margin: 2em 0;
text-align: center;
max-height: 30vh;
}
footer a {
color: #919191 !important;
.footer a {
color: inherit;
text-decoration: underline;
}
footer span {
margin: 4px 0;
display: block;
}
/* keyframes */
@keyframes spin {
@ -332,206 +282,190 @@ footer span {
}
}
/* Control Bar */
@media screen and (max-width: 640px) {
.video-js .vjs-control-bar,
.vjs-menu-button-popup .vjs-menu .vjs-menu-content {
overflow-x: scroll;
}
}
ul.vjs-menu-content::-webkit-scrollbar {
display: none;
}
.vjs-user-inactive {
cursor: none;
}
.video-js .vjs-text-track-display > div > div > div {
background-color: rgba(0, 0, 0, 0.75) !important;
border-radius: 9px !important;
padding: 5px !important;
}
.vjs-play-control,
.vjs-volume-panel,
.vjs-current-time,
.vjs-time-control,
.vjs-duration,
.vjs-progress-control,
.vjs-remaining-time {
order: 1;
}
.vjs-captions-button {
order: 2;
}
.vjs-quality-selector,
.video-js .vjs-http-source-selector {
order: 3;
}
.vjs-playback-rate {
order: 4;
}
.vjs-share-control {
order: 5;
}
.vjs-fullscreen-control {
order: 6;
}
.vjs-playback-rate > .vjs-menu {
width: 50px;
}
.vjs-control-bar {
display: flex;
flex-direction: row;
scrollbar-width: none;
}
.vjs-control-bar::-webkit-scrollbar {
display: none;
}
.video-js .vjs-icon-cog {
font-size: 18px;
}
.video-js .vjs-control-bar,
.vjs-menu-button-popup .vjs-menu .vjs-menu-content {
background-color: rgba(35, 35, 35, 0.75);
}
.vjs-menu li.vjs-menu-item:focus,
.vjs-menu li.vjs-menu-item:hover {
background-color: rgba(255, 255, 255, 0.75);
color: rgba(49, 49, 51, 0.75);
}
.vjs-menu li.vjs-selected,
.vjs-menu li.vjs-selected:focus,
.vjs-menu li.vjs-selected:hover {
background-color: rgba(0, 182, 240, 0.75);
}
/* Progress Bar */
.video-js .vjs-slider {
background-color: rgba(15, 15, 15, 0.5);
}
fieldset > select,
span > select {
color: rgba(49, 49, 51, 1);
}
.video-js .vjs-load-progress,
.video-js .vjs-load-progress div {
background: rgba(87, 87, 88, 1);
}
.video-js .vjs-slider:hover,
.video-js button:hover {
color: rgba(0, 182, 240, 1);
}
.video-js .vjs-play-progress {
background-color: rgba(0, 182, 240, 1);
}
/* Overlay */
.video-js .vjs-overlay {
background-color: rgba(35, 35, 35, 0.75);
color: rgba(255, 255, 255, 1);
}
/* ProgressBar marker */
.vjs-marker {
background-color: rgba(255, 255, 255, 1);
z-index: 0;
}
/* Big "Play" Button */
.video-js .vjs-big-play-button {
background-color: rgba(35, 35, 35, 0.5);
}
.video-js:hover .vjs-big-play-button {
background-color: rgba(35, 35, 35, 0.75);
}
.video-js .vjs-current-time,
.video-js .vjs-time-divider,
.video-js .vjs-duration {
display: block;
}
.video-js .vjs-time-divider {
min-width: 0px;
padding-left: 0px;
padding-right: 0px;
}
.video-js .vjs-poster {
background-size: cover;
object-fit: cover;
}
.player-dimensions.vjs-fluid {
padding-top: 82vh;
}
video.video-js {
position: absolute;
height: 100%;
}
#player-container {
position: relative;
padding-bottom: 82vh;
height: 0;
}
.pure-control-group label {
word-wrap: normal;
}
/*
* Light theme
*/
.light-theme a:hover,
.light-theme a:active,
.light-theme summary:hover {
color: #075A9E !important;
.video-js.player-style-invidious {
/* This is already the default */
}
.light-theme a.pure-button-primary:hover {
color: #fff !important;
.video-js.player-style-youtube .vjs-control-bar {
display: flex;
flex-direction: row;
}
.light-theme a {
color: #335d7a;
text-decoration: none;
.video-js.player-style-youtube .vjs-big-play-button {
/*
Styles copied from video-js.min.css, definition of
.vjs-big-play-centered .vjs-big-play-button
*/
top: 50%;
left: 50%;
margin-top: -0.81666em;
margin-left: -1.5em;
}
/* All links that do not fit with the default color goes here */
.light-theme a:not([data-id]) > .icon,
.light-theme .pure-u-lg-1-5 > .h-box > a[href^="/watch?"],
.light-theme .playlist-restricted > ol > li > a {
color: #303030;
}
.light-theme .pure-menu-heading {
color: #565d64;
}
@media (prefers-color-scheme: light) {
.no-theme a:hover,
.no-theme a:active,
.no-theme summary:hover {
color: #075A9E !important;
}
.no-theme a.pure-button-primary:hover {
color: #fff !important;
}
.no-theme a {
color: #335d7a;
text-decoration: none;
}
/* All links that do not fit with the default color goes here */
.no-theme a:not([data-id]) > .icon,
.no-theme .pure-u-lg-1-5 > .h-box > a[href^="/watch?"],
.no-theme .playlist-restricted > ol > li > a {
color: #303030;
}
.light-theme .pure-menu-heading {
color: #565d64;
}
}
/*
* Dark theme
*/
.dark-theme a:hover,
.dark-theme a:active,
.dark-theme summary:hover {
color: rgb(0, 182, 240);
}
.dark-theme a {
color: #a0a0a0;
text-decoration: none;
}
body.dark-theme {
background-color: rgba(35, 35, 35, 1);
color: #f0f0f0;
}
.dark-theme .pure-form legend {
color: #f0f0f0;
}
.dark-theme .pure-menu-heading {
color: #f0f0f0;
}
.dark-theme input,
.dark-theme select,
.dark-theme textarea {
color: rgba(35, 35, 35, 1);
}
.dark-theme .pure-form input[type="file"] {
color: #f0f0f0;
}
.dark-theme .searchbar input {
background-color: inherit;
color: inherit;
}
@media (prefers-color-scheme: dark) {
.no-theme a:hover,
.no-theme a:active {
color: rgb(0, 182, 240);
}
.no-theme a {
color: #a0a0a0;
text-decoration: none;
}
body.no-theme {
background-color: rgba(35, 35, 35, 1);
color: #f0f0f0;
}
.no-theme .pure-form legend {
color: #f0f0f0;
}
.no-theme .pure-menu-heading {
color: #f0f0f0;
}
.no-theme input,
.no-theme select,
.no-theme textarea {
color: rgba(35, 35, 35, 1);
}
.no-theme .pure-form input[type="file"] {
color: #f0f0f0;
}
.no-theme .searchbar input {
background-color: inherit;
color: inherit;
}
}
/*With commit d9528f5 all contents of the page is now within a flexbox. However,
the hr element is rendered improperly within one.
See https://stackoverflow.com/a/34372979 for more info */
hr {
margin: 10px 0 10px 0;
}
/* Description Expansion Styling*/
#descexpansionbutton {
display: none
}
#descexpansionbutton ~ div {
overflow: hidden;
height: 8.3em;
}
#descexpansionbutton:checked ~ div {
overflow: unset;
height: 100%;
}
#descexpansionbutton ~ label {
order: 1;
margin-top: 20px;
}
/* Bidi (bidirectional text) support */
h1,
h2,
h3,
h4,
h5,
p,
#descriptionWrapper,
#description-box {
unicode-bidi: plaintext;
text-align: start;
}
#descriptionWrapper {
max-width: 600px;
white-space: pre-wrap;
}
/* Center the "invidious" logo on the search page */
#logo > h1 { text-align: center; }
/* IE11 fixes */
:-ms-input-placeholder { color: #888; }
/* Wider settings name to less word wrap */
.pure-form-aligned .pure-control-group label { width: 19em; }

View File

@ -8,19 +8,3 @@
height: auto;
z-index: -100;
}
.watch-on-invidious {
font-size: 1.3em !important;
font-weight: bold;
white-space: nowrap;
margin: 0 1em 0 1em !important;
order: 3;
}
.watch-on-invidious > a {
color: white;
}
.watch-on-invidious > a:hover {
color: rgba(0, 182, 240, 1);;
}

View File

@ -1,16 +0,0 @@
#search-widget {
text-align: center;
margin: 20vh 0 50px 0;
}
#logo > h1 {
font-size: 3.5em;
margin: 0;
padding: 0;
}
@media screen and (max-width: 1500px) and (max-height: 1000px) {
#logo > h1 {
font-size: 10vmin;
}
}

16
assets/css/lighttheme.css Normal file
View File

@ -0,0 +1,16 @@
a:hover,
a:active {
color: #167ac6 !important;
}
a {
color: #61809b;
text-decoration: none;
}
/* All links that do not fit with the default color goes here */
a:not([data-id]) > .icon,
.pure-u-lg-1-5 > .h-box > a[href^="/watch?"],
.playlist-restricted > ol > li > a {
color: #303030;
}

View File

@ -1,261 +0,0 @@
/* Youtube player style */
.video-js.player-style-youtube .vjs-progress-control {
height: 0;
}
.video-js.player-style-youtube .vjs-progress-control .vjs-progress-holder, .video-js.player-style-youtube .vjs-progress-control {
position: absolute;
right: 0;
left: 0;
width: 100%;
margin: 0;
}
.video-js.player-style-youtube .vjs-control-bar {
background: linear-gradient(rgba(0,0,0,0.1), rgba(0, 0, 0,0.5));
}
.video-js.player-style-youtube .vjs-slider {
background-color: rgba(255,255,255,0.2);
}
.video-js.player-style-youtube .vjs-load-progress > div {
background-color: rgba(255,255,255,0.5);
}
.video-js.player-style-youtube .vjs-play-progress {
background-color: red;
}
.video-js.player-style-youtube .vjs-progress-control:hover .vjs-progress-holder {
font-size: 15px;
}
.video-js.player-style-youtube .vjs-control-bar > .vjs-spacer {
flex: 1;
order: 2;
}
.video-js.player-style-youtube .vjs-play-progress .vjs-time-tooltip {
display: none;
}
.video-js.player-style-youtube .vjs-play-progress::before {
color: red;
font-size: 0.85em;
display: none;
}
.video-js.player-style-youtube .vjs-progress-holder:hover .vjs-play-progress::before {
display: unset;
}
.video-js.player-style-youtube .vjs-control-bar {
display: flex;
flex-direction: row;
}
.video-js.player-style-youtube .vjs-big-play-button {
/*
Styles copied from video-js.min.css, definition of
.vjs-big-play-centered .vjs-big-play-button
*/
top: 50%;
left: 50%;
margin-top: -0.81666em;
margin-left: -1.5em;
}
.video-js.player-style-youtube .vjs-menu-button-popup .vjs-menu {
margin-bottom: 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;}
ul.vjs-menu-content::-webkit-scrollbar {
display: none;
}
.vjs-user-inactive {
cursor: none;
}
.video-js .vjs-text-track-display > div > div > div {
background-color: rgba(0, 0, 0, 0.75) !important;
border-radius: 9px !important;
padding: 5px !important;
}
.vjs-play-control,
.vjs-volume-panel,
.vjs-current-time,
.vjs-time-control,
.vjs-duration,
.vjs-progress-control,
.vjs-remaining-time {
order: 1;
}
.vjs-captions-button {
order: 2;
}
.vjs-audio-button {
order: 3;
}
.vjs-quality-selector,
.video-js .vjs-http-source-selector {
order: 4;
}
.vjs-playback-rate {
order: 5;
}
.vjs-share-control {
order: 6;
}
.vjs-fullscreen-control {
order: 7;
}
.vjs-playback-rate > .vjs-menu {
width: 50px;
}
.vjs-control-bar {
display: flex;
flex-direction: row;
scrollbar-width: none;
}
.vjs-control-bar::-webkit-scrollbar {
display: none;
}
.video-js .vjs-icon-cog {
font-size: 18px;
}
.video-js .vjs-control-bar,
.vjs-menu-button-popup .vjs-menu .vjs-menu-content {
background-color: rgba(35, 35, 35, 0.75);
}
.vjs-menu li.vjs-menu-item:focus,
.vjs-menu li.vjs-menu-item:hover {
background-color: rgba(255, 255, 255, 0.75);
color: rgba(49, 49, 51, 0.75);
}
.vjs-menu li.vjs-selected,
.vjs-menu li.vjs-selected:focus,
.vjs-menu li.vjs-selected:hover {
background-color: rgba(0, 182, 240, 0.75);
}
/* Progress Bar */
.video-js .vjs-slider {
background-color: rgba(15, 15, 15, 0.5);
}
.video-js .vjs-load-progress,
.video-js .vjs-load-progress div {
background: rgba(87, 87, 88, 1);
}
.video-js .vjs-slider:hover,
.video-js button:hover {
color: rgba(0, 182, 240, 1);
}
.video-js.player-style-invidious .vjs-play-progress {
background-color: rgba(0, 182, 240, 1);
}
vjs-menu-content
/* Overlay */
.video-js .vjs-overlay {
background-color: rgba(35, 35, 35, 0.75);
color: rgba(255, 255, 255, 1);
}
/* ProgressBar marker */
.vjs-marker {
background-color: rgba(255, 255, 255, 1);
z-index: 0;
}
/* Big "Play" Button */
.video-js .vjs-big-play-button {
background-color: rgba(35, 35, 35, 0.5);
}
.video-js:hover .vjs-big-play-button {
background-color: rgba(35, 35, 35, 0.75);
}
.video-js .vjs-current-time,
.video-js .vjs-time-divider,
.video-js .vjs-duration {
display: block;
}
.video-js .vjs-time-divider {
min-width: 0px;
padding-left: 0px;
padding-right: 0px;
}
.video-js .vjs-poster {
background-size: cover;
object-fit: cover;
}
.player-dimensions.vjs-fluid {
padding-top: 82vh;
}
video.video-js {
position: absolute;
height: 100%;
}
#player-container {
position: relative;
padding-left: 0;
padding-right: 0;
margin-left: 1em;
margin-right: 1em;
padding-bottom: 82vh;
height: 0;
}
.mobile-operations-bar {
display: flex;
position: absolute;
top: 0;
right: 1px !important;
left: initial !important;
width: initial !important;
}
.mobile-operations-bar ul {
position: absolute !important;
bottom: unset !important;
top: 1.5em;
}
@media screen and (max-width: 700px) {
.video-js .vjs-share {
justify-content: unset;
}
}
@media screen and (max-width: 650px) {
.vjs-modal-dialog-content {
overflow-x: hidden;
}
}

View File

@ -1,121 +0,0 @@
summary {
/* This should hide the marker */
display: block;
font-size: 1.17em;
font-weight: bold;
margin: 0 auto 10px auto;
cursor: pointer;
}
summary::-webkit-details-marker,
summary::marker { display: none; }
summary:before {
border-radius: 5px;
content: "[ + ]";
margin: -2px 10px 0 10px;
padding: 1px 0 3px 0;
text-align: center;
width: 40px;
}
details[open] > summary:before { content: "[ ]"; }
#filters-box {
padding: 10px 20px 20px 10px;
margin: 10px 15px;
}
#filters-flex {
display: flex;
flex-wrap: wrap;
flex-direction: row;
align-items: flex-start;
align-content: flex-start;
justify-content: flex-start;
}
fieldset, legend {
display: contents !important;
border: none !important;
margin: 0 !important;
padding: 0 !important;
}
.filter-column {
display: inline-block;
display: inline-flex;
width: max-content;
min-width: max-content;
max-width: 16em;
margin: 15px;
flex-grow: 2;
flex-basis: auto;
flex-direction: column;
}
.filter-name, .filter-options {
display: block;
padding: 5px 10px;
margin: 0;
text-align: start;
}
.filter-options div { margin: 6px 0; }
.filter-options div * { vertical-align: middle; }
.filter-options label { margin: 0 10px; }
#filters-apply {
text-align: right; /* IE11 only */
text-align: end; /* Override for compatible browsers */
}
/* Error message */
.no-results-error {
text-align: center;
line-height: 180%;
font-size: 110%;
padding: 15px 15px 125px 15px;
}
/* Responsive rules */
@media only screen and (max-width: 800px) {
summary { font-size: 1.30em; }
#filters-box {
margin: 10px 0 0 0;
padding: 0;
}
#filters-apply {
text-align: center;
padding: 15px;
}
}
/* Light theme */
.light-theme #filters-box {
background: #dfdfdf;
}
@media (prefers-color-scheme: light) {
.no-theme #filters-box {
background: #dfdfdf;
}
}
/* Dark theme */
.dark-theme #filters-box {
background: #373737;
}
@media (prefers-color-scheme: dark) {
.no-theme #filters-box {
background: #373737;
}
}

1
assets/css/video-js.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
/**
* videojs-http-source-selector
* @version 1.1.6
* @copyright 2019 Justin Fujita <Justin@pivotshare.com>
* @license MIT
*/
.video-js.vjs-http-source-selector{display:block}

View File

@ -0,0 +1 @@
.video-js .vjs-overlay{color:#fff;position:absolute;text-align:center}.video-js .vjs-overlay-no-background{max-width:33%}.video-js .vjs-overlay-background{background-color:#646464;background-color:rgba(255,255,255,0.4);border-radius:3px;padding:10px;width:33%}.video-js .vjs-overlay-top-left{top:5px;left:5px}.video-js .vjs-overlay-top{left:50%;margin-left:-16.5%;top:5px}.video-js .vjs-overlay-top-right{right:5px;top:5px}.video-js .vjs-overlay-right{right:5px;top:50%;transform:translateY(-50%)}.video-js .vjs-overlay-bottom-right{bottom:3.5em;right:5px}.video-js .vjs-overlay-bottom{bottom:3.5em;left:50%;margin-left:-16.5%}.video-js .vjs-overlay-bottom-left{bottom:3.5em;left:5px}.video-js .vjs-overlay-left{left:5px;top:50%;transform:translateY(-50%)}.video-js .vjs-overlay-center{left:50%;margin-left:-16.5%;top:50%;transform:translateY(-50%)}.video-js .vjs-no-flex .vjs-overlay-left,.video-js .vjs-no-flex .vjs-overlay-center,.video-js .vjs-no-flex .vjs-overlay-right{margin-top:-15px}

View File

@ -0,0 +1,7 @@
/**
* videojs-share
* @version 3.2.1
* @copyright 2019 Mikhail Khazov <mkhazov.work@gmail.com>
* @license MIT
*/
.video-js.vjs-videojs-share_open .vjs-modal-dialog .vjs-modal-dialog-content{display:flex;align-items:center;padding:0;background-image:linear-gradient(to bottom, rgba(0,0,0,0.77), rgba(0,0,0,0.75))}.video-js.vjs-videojs-share_open .vjs-modal-dialog .vjs-close-button{position:absolute;right:0;top:5px;width:30px;height:30px;color:#fff;cursor:pointer;opacity:0.9;transition:opacity 0.25s ease-out}.video-js.vjs-videojs-share_open .vjs-modal-dialog .vjs-close-button:before{content:'×';font-size:20px;line-height:15px}.video-js.vjs-videojs-share_open .vjs-modal-dialog .vjs-close-button:hover{opacity:1}.video-js .vjs-share{display:flex;flex-direction:column;justify-content:space-around;align-items:center;width:100%;height:100%;max-height:400px}.video-js .vjs-share__top,.video-js .vjs-share__middle,.video-js .vjs-share__bottom{display:flex}.video-js .vjs-share__top,.video-js .vjs-share__middle{flex-direction:column;justify-content:space-between}.video-js .vjs-share__middle{padding:0 25px}.video-js .vjs-share__title{align-self:center;font-size:22px;color:#fff}.video-js .vjs-share__subtitle{width:100%;margin:0 auto 12px;font-size:16px;color:#fff;opacity:0.7}.video-js .vjs-share__short-link-wrapper{position:relative;display:block;width:100%;height:40px;margin:0 auto;margin-bottom:15px;border:0;color:rgba(255,255,255,0.65);background-color:#363636;outline:none;overflow:hidden;flex-shrink:0}.video-js .vjs-share__short-link{display:block;width:100%;height:100%;padding:0 40px 0 15px;border:0;color:rgba(255,255,255,0.65);background-color:#363636;outline:none}.video-js .vjs-share__btn{position:absolute;right:0;bottom:0;height:40px;width:40px;display:flex;align-items:center;padding:0 11px;border:0;color:#fff;background-color:#2e2e2e;background-size:18px 19px;background-position:center;background-repeat:no-repeat;cursor:pointer;outline:none;transition:width 0.3s ease-out, padding 0.3s ease-out}.video-js .vjs-share__btn svg{flex-shrink:0}.video-js .vjs-share__btn span{position:relative;padding-left:10px;opacity:0;transition:opacity 0.3s ease-out}.video-js .vjs-share__btn:hover{justify-content:center;width:100%;padding:0 40px;background-image:none}.video-js .vjs-share__btn:hover span{opacity:1}.video-js .vjs-share__socials{display:flex;flex-wrap:wrap;justify-content:center;align-content:flex-start;transition:width 0.3s ease-out, height 0.3s ease-out}.video-js .vjs-share__social{display:flex;justify-content:center;align-items:center;flex-shrink:0;width:32px;height:32px;margin-right:6px;margin-bottom:6px;cursor:pointer;font-size:8px;transition:transform 0.3s ease-out, filter 0.2s ease-out;border:none;outline:none}.video-js .vjs-share__social:hover{filter:brightness(115%)}.video-js .vjs-share__social svg{overflow:visible;max-height:24px}.video-js .vjs-share__social_vk{background-color:#5d7294}.video-js .vjs-share__social_ok{background-color:#ed7c20}.video-js .vjs-share__social_mail,.video-js .vjs-share__social_email{background-color:#134785}.video-js .vjs-share__social_tw{background-color:#76aaeb}.video-js .vjs-share__social_reddit{background-color:#ff4500}.video-js .vjs-share__social_fbFeed{background-color:#475995}.video-js .vjs-share__social_messenger{background-color:#0084ff}.video-js .vjs-share__social_gp{background-color:#d53f35}.video-js .vjs-share__social_linkedin{background-color:#0077b5}.video-js .vjs-share__social_viber{background-color:#766db5}.video-js .vjs-share__social_telegram{background-color:#4bb0e2}.video-js .vjs-share__social_whatsapp{background-color:#78c870}.video-js .vjs-share__bottom{justify-content:center}@media (max-height: 220px){.video-js .vjs-share .hidden-xs{display:none}}@media (max-height: 350px){.video-js .vjs-share .hidden-sm{display:none}}@media (min-height: 400px){.video-js .vjs-share__title{margin-bottom:15px}.video-js .vjs-share__short-link-wrapper{margin-bottom:30px}}@media (min-width: 320px){.video-js.vjs-videojs-share_open .vjs-modal-dialog .vjs-close-button{right:5px;top:10px}}@media (min-width: 660px){.video-js.vjs-videojs-share_open .vjs-modal-dialog .vjs-close-button{right:20px;top:20px}.video-js .vjs-share__social{width:40px;height:40px}}

View File

@ -0,0 +1,7 @@
/**
* videojs-vtt-thumbnails
* @version 0.0.13
* @copyright 2019 Chris Boustead <chris@forgemotion.com>
* @license MIT
*/
.video-js.vjs-vtt-thumbnails{display:block}.video-js .vjs-vtt-thumbnail-display{position:absolute;bottom:85%;pointer-events:none;box-shadow:0 0 7px rgba(0,0,0,0.6)}

1
assets/css/videojs.markers.min.css vendored Normal file
View File

@ -0,0 +1 @@
.vjs-marker{position:absolute;left:0;bottom:0;opacity:1;height:100%;transition:opacity .2s ease;-webkit-transition:opacity .2s ease;-moz-transition:opacity .2s ease;z-index:100}.vjs-marker:hover{cursor:pointer;-webkit-transform:scale(1.3,1.3);-moz-transform:scale(1.3,1.3);-o-transform:scale(1.3,1.3);-ms-transform:scale(1.3,1.3);transform:scale(1.3,1.3)}.vjs-tip{visibility:hidden;display:block;opacity:.8;padding:5px;font-size:10px;position:absolute;bottom:14px;z-index:100000}.vjs-tip .vjs-tip-arrow{background:url(data:image/gif;base64,R0lGODlhCQAJAIABAAAAAAAAACH5BAEAAAEALAAAAAAJAAkAAAIRjAOnwIrcDJxvwkplPtchVQAAOw==) no-repeat top left;bottom:0;left:50%;margin-left:-4px;background-position:bottom left;position:absolute;width:9px;height:5px}.vjs-tip .vjs-tip-inner{border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;padding:5px 8px 4px 8px;background-color:#000;color:#fff;max-width:200px;text-align:center}.vjs-break-overlay{visibility:hidden;position:absolute;z-index:100000;top:0}.vjs-break-overlay .vjs-break-overlay-text{padding:9px;text-align:center}

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="512pt" height="512pt" version="1.0" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><g><rect x="-.0072516" y=".00056299" width="512.01" height="512.02" fill="#575757" stroke-width=".063019"/><path d="m247.17 455.95c-19.792-0.78921-38.719-4.2564-57.154-10.47-60.968-20.55-108.68-68.579-127-127.86-7.8955-25.538-10.062-53.943-6.2586-82.067 3.7105-27.439 13.603-53.515 29.342-77.344 12.069-18.273 29.138-36.277 47.228-49.816 36.891-27.61 85.944-42.49 132.38-40.157 25.88 1.3001 49.939 6.765 73.106 16.606 8.1948 3.481 20.024 9.6845 27.696 14.525 14.15 8.9272 22.367 15.498 34.482 27.573 13.254 13.211 22.128 24.276 30.398 37.906 7.2081 11.879 14.099 27.15 18.229 40.397 1.5996 5.1305 4.442 16.456 5.6852 22.653 2.3908 11.917 2.6998 15.722 2.7049 33.312 6e-3 18.515-0.46256 24.413-2.9166 36.758-9.3274 46.92-35.58 88.167-74.872 117.64-22.814 17.112-50.027 29.535-78.547 35.858-16.714 3.7059-35.421 5.2453-54.498 4.4846zm-35.1-78.786c-5.3e-4 -0.52647-0.0741-2.0564-0.16311-3.3999l-0.16178-2.4427-4.7018-0.26271c-4.0477-0.22614-4.7968-0.33363-5.3847-0.77253-2.0235-1.5108-1.4679-6.0695 2.2494-18.457 0.8637-2.8781 3.3371-11.321 5.4966-18.762 2.1594-7.4409 5.2002-17.836 6.7573-23.101 1.5571-5.2648 4.1948-14.282 5.8615-20.038 1.6667-5.7562 3.6145-12.4 4.3284-14.764 0.71391-2.3641 3.2583-11.037 5.6542-19.272 4.9475-17.007 8.1626-27.723 8.9438-29.811 0.51852-1.3858 0.54785-1.4139 0.99761-0.95317 0.25486 0.26106 3.8462 7.3667 7.9807 15.79 4.1345 8.4236 13.089 26.573 19.898 40.331 17.188 34.73 37.849 76.578 43.261 87.622l4.5356 9.257 11.359-0.0895c6.2475-0.0492 11.615-0.19623 11.929-0.32672 0.5614-0.23385 0.54167-0.2959-1.3723-4.3176-1.068-2.2442-8.1436-16.601-15.724-31.904-48.687-98.293-61.22-123.86-67.889-138.48-4.7022-10.309-6.9031-14.807-7.7139-15.762-0.82931-0.97742-1.6319-1.0638-2.3704-0.25525-1.1993 1.313-4.1046 10.063-9.3869 28.27-2.0569 7.0899-6.5372 22.425-9.9562 34.077-6.6396 22.629-8.5182 29.037-14.33 48.883-2.0354 6.9495-4.7977 16.369-6.1385 20.931-1.3408 4.5628-4.033 13.81-5.9826 20.549-4.304 14.877-6.136 20.889-7.3886 24.25-2.1371 5.7334-2.5723 6.3292-4.9216 6.7384-0.88855 0.15472-2.4102 0.28196-3.3815 0.28275-2.1993 3e-3 -3.5494 0.36339-4.0558 1.0863-0.42176 0.60215-0.56421 4.8802-0.18251 5.4812 0.20573 0.32388 2.4672 0.37414 23.34 0.51873l8.6151 0.0597-7e-4 -0.95723zm36.751-205.59c4.3282-0.92335 8.4607-4.943 9.4374-9.1796 0.36569-1.5862 0.32543-4.9758-0.077-6.4799-0.85108-3.1813-3.2688-6.291-6.039-7.7675-3.8111-2.0313-9.456-2.0295-13.272 5e-3 -5.9828 3.1888-8.1556 11.089-4.7878 17.408 2.6995 5.0648 8.3611 7.3754 14.738 6.015z" fill="#f0f0f0" stroke-width=".025526"/></g><g transform="matrix(.069892 0 0 -.069892 44.236 474.48)"><path d="m2787 4669c-124-65-123-255 3-319 86-44 196-16 247 62 58 87 26 211-67 258-51 26-132 26-183-1z" fill="#00b6f0" stroke="#00b6f0" stroke-width="4.25"/><path d="m2882 4108c-12-16-63-166-102-303-30-104-101-350-165-565-20-69-58-199-85-290-26-91-64-221-85-290-20-69-58-199-85-290-26-91-64-221-85-290-20-69-57-195-81-280-59-207-93-299-115-310-10-6-35-10-56-10-73 0-84-8-81-54l3-41 228-3 228-2-3 47-3 48-73 3c-66 3-74 5-84 27-13 28 0 104 37 225 13 41 47 156 75 255s66 230 85 290c18 61 56 191 85 290 28 99 66 230 85 290 18 61 56 191 85 290 85 297 123 419 131 429 5 5 17-11 28-35 10-24 192-393 403-819s447-902 523-1058l139-282h168c92 0 168 4 168 8s-75 158-166 342c-588 1183-969 1958-1033 2100-29 63-69 151-89 195-44 95-58 110-80 83z" fill="#575757"/></g></svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,249 +0,0 @@
'use strict';
// Contains only auxiliary methods
// May be included and executed unlimited number of times without any consequences
// Polyfills for IE11
Array.prototype.find = Array.prototype.find || function (condition) {
return this.filter(condition)[0];
};
Array.from = Array.from || function (source) {
return Array.prototype.slice.call(source);
};
NodeList.prototype.forEach = NodeList.prototype.forEach || function (callback) {
Array.from(this).forEach(callback);
};
String.prototype.includes = String.prototype.includes || function (searchString) {
return this.indexOf(searchString) >= 0;
};
String.prototype.startsWith = String.prototype.startsWith || function (prefix) {
return this.substr(0, prefix.length) === prefix;
};
Math.sign = Math.sign || function(x) {
x = +x;
if (!x) return x; // 0 and NaN
return x > 0 ? 1 : -1;
};
if (!window.hasOwnProperty('HTMLDetailsElement') && !window.hasOwnProperty('mockHTMLDetailsElement')) {
window.mockHTMLDetailsElement = true;
const style = 'details:not([open]) > :not(summary) {display: none}';
document.head.appendChild(document.createElement('style')).textContent = style;
addEventListener('click', function (e) {
if (e.target.nodeName !== 'SUMMARY') return;
const details = e.target.parentElement;
if (details.hasAttribute('open'))
details.removeAttribute('open');
else
details.setAttribute('open', '');
});
}
// Monstrous global variable for handy code
// Includes: clamp, xhr, storage.{get,set,remove}
window.helpers = window.helpers || {
/**
* https://en.wikipedia.org/wiki/Clamping_(graphics)
* @param {Number} num Source number
* @param {Number} min Low border
* @param {Number} max High border
* @returns {Number} Clamped value
*/
clamp: function (num, min, max) {
if (max < min) {
var t = max; max = min; min = t; // swap max and min
}
if (max < num)
return max;
if (min > num)
return min;
return num;
},
/** @private */
_xhr: function (method, url, options, callbacks) {
const xhr = new XMLHttpRequest();
xhr.open(method, url);
// Default options
xhr.responseType = 'json';
xhr.timeout = 10000;
// Default options redefining
if (options.responseType)
xhr.responseType = options.responseType;
if (options.timeout)
xhr.timeout = options.timeout;
if (method === 'POST')
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// better than onreadystatechange because of 404 codes https://stackoverflow.com/a/36182963
xhr.onloadend = function () {
if (xhr.status === 200) {
if (callbacks.on200) {
// fix for IE11. It doesn't convert response to JSON
if (xhr.responseType === '' && typeof(xhr.response) === 'string')
callbacks.on200(JSON.parse(xhr.response));
else
callbacks.on200(xhr.response);
}
} else {
// handled by onerror
if (xhr.status === 0) return;
if (callbacks.onNon200)
callbacks.onNon200(xhr);
}
};
xhr.ontimeout = function () {
if (callbacks.onTimeout)
callbacks.onTimeout(xhr);
};
xhr.onerror = function () {
if (callbacks.onError)
callbacks.onError(xhr);
};
if (options.payload)
xhr.send(options.payload);
else
xhr.send();
},
/** @private */
_xhrRetry: function(method, url, options, callbacks) {
if (options.retries <= 0) {
console.warn('Failed to pull', options.entity_name);
if (callbacks.onTotalFail)
callbacks.onTotalFail();
return;
}
helpers._xhr(method, url, options, callbacks);
},
/**
* @callback callbackXhrOn200
* @param {Object} response - xhr.response
*/
/**
* @callback callbackXhrError
* @param {XMLHttpRequest} xhr
*/
/**
* @param {'GET'|'POST'} method - 'GET' or 'POST'
* @param {String} url - URL to send request to
* @param {Object} options - other XHR options
* @param {XMLHttpRequestBodyInit} [options.payload=null] - payload for POST-requests
* @param {'arraybuffer'|'blob'|'document'|'json'|'text'} [options.responseType=json]
* @param {Number} [options.timeout=10000]
* @param {Number} [options.retries=1]
* @param {String} [options.entity_name='unknown'] - string to log
* @param {Number} [options.retry_timeout=1000]
* @param {Object} callbacks - functions to execute on events fired
* @param {callbackXhrOn200} [callbacks.on200]
* @param {callbackXhrError} [callbacks.onNon200]
* @param {callbackXhrError} [callbacks.onTimeout]
* @param {callbackXhrError} [callbacks.onError]
* @param {callbackXhrError} [callbacks.onTotalFail] - if failed after all retries
*/
xhr: function(method, url, options, callbacks) {
if (!options.retries || options.retries <= 1) {
helpers._xhr(method, url, options, callbacks);
return;
}
if (!options.entity_name) options.entity_name = 'unknown';
if (!options.retry_timeout) options.retry_timeout = 1000;
const retries_total = options.retries;
let currentTry = 1;
const retry = function () {
console.warn('Pulling ' + options.entity_name + ' failed... ' + (currentTry++) + '/' + retries_total);
setTimeout(function () {
options.retries--;
helpers._xhrRetry(method, url, options, callbacks);
}, options.retry_timeout);
};
// Pack retry() call into error handlers
callbacks._onError = callbacks.onError;
callbacks.onError = function (xhr) {
if (callbacks._onError)
callbacks._onError(xhr);
retry();
};
callbacks._onTimeout = callbacks.onTimeout;
callbacks.onTimeout = function (xhr) {
if (callbacks._onTimeout)
callbacks._onTimeout(xhr);
retry();
};
helpers._xhrRetry(method, url, options, callbacks);
},
/**
* @typedef {Object} invidiousStorage
* @property {(key:String) => Object} get
* @property {(key:String, value:Object)} set
* @property {(key:String)} remove
*/
/**
* Universal storage, stores and returns JS objects. Uses inside localStorage or cookies
* @type {invidiousStorage}
*/
storage: (function () {
// access to localStorage throws exception in Tor Browser, so try is needed
let localStorageIsUsable = false;
try{localStorageIsUsable = !!localStorage.setItem;}catch(e){}
if (localStorageIsUsable) {
return {
get: function (key) {
if (!localStorage[key]) return;
try {
return JSON.parse(decodeURIComponent(localStorage[key]));
} catch(e) {
// Erase non parsable value
helpers.storage.remove(key);
}
},
set: function (key, value) { localStorage[key] = encodeURIComponent(JSON.stringify(value)); },
remove: function (key) { localStorage.removeItem(key); }
};
}
// TODO: fire 'storage' event for cookies
console.info('Storage: localStorage is disabled or unaccessible. Cookies used as fallback');
return {
get: function (key) {
const cookiePrefix = key + '=';
function findCallback(cookie) {return cookie.startsWith(cookiePrefix);}
const matchedCookie = document.cookie.split('; ').find(findCallback);
if (matchedCookie) {
const cookieBody = matchedCookie.replace(cookiePrefix, '');
if (cookieBody.length === 0) return;
try {
return JSON.parse(decodeURIComponent(cookieBody));
} catch(e) {
// Erase non parsable value
helpers.storage.remove(key);
}
}
},
set: function (key, value) {
const cookie_data = encodeURIComponent(JSON.stringify(value));
// Set expiration in 2 year
const date = new Date();
date.setFullYear(date.getFullYear()+2);
document.cookie = key + '=' + cookie_data + '; expires=' + date.toGMTString();
},
remove: function (key) {
document.cookie = key + '=; Max-Age=0';
}
};
})()
};

View File

@ -1,13 +1,19 @@
'use strict';
var community_data = JSON.parse(document.getElementById('community_data').textContent);
var community_data = JSON.parse(document.getElementById('community_data').innerHTML);
String.prototype.supplant = function (o) {
return this.replace(/{([^{}]*)}/g, function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
});
}
function hide_youtube_replies(event) {
var target = event.target;
var sub_text = target.getAttribute('data-inner-text');
var inner_text = target.getAttribute('data-sub-text');
sub_text = target.getAttribute('data-inner-text');
inner_text = target.getAttribute('data-sub-text');
var body = target.parentNode.parentNode.children[1];
body = target.parentNode.parentNode.children[1];
body.style.display = 'none';
target.innerHTML = sub_text;
@ -19,10 +25,10 @@ function hide_youtube_replies(event) {
function show_youtube_replies(event) {
var target = event.target;
var sub_text = target.getAttribute('data-inner-text');
var inner_text = target.getAttribute('data-sub-text');
sub_text = target.getAttribute('data-inner-text');
inner_text = target.getAttribute('data-sub-text');
var body = target.parentNode.parentNode.children[1];
body = target.parentNode.parentNode.children[1];
body.style.display = '';
target.innerHTML = sub_text;
@ -31,6 +37,13 @@ function show_youtube_replies(event) {
target.setAttribute('data-sub-text', sub_text);
}
function number_with_separator(val) {
while (/(\d+)(\d{3})/.test(val.toString())) {
val = val.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
}
return val;
}
function get_youtube_replies(target, load_more) {
var continuation = target.getAttribute('data-continuation');
@ -44,39 +57,47 @@ function get_youtube_replies(target, load_more) {
'&hl=' + community_data.preferences.locale +
'&thin_mode=' + community_data.preferences.thin_mode +
'&continuation=' + continuation;
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('GET', url, true);
helpers.xhr('GET', url, {}, {
on200: function (response) {
if (load_more) {
body = body.parentNode.parentNode;
body.removeChild(body.lastElementChild);
body.innerHTML += response.contentHtml;
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
if (load_more) {
body = body.parentNode.parentNode;
body.removeChild(body.lastElementChild);
body.innerHTML += xhr.response.contentHtml;
} else {
body.removeChild(body.lastElementChild);
var p = document.createElement('p');
var a = document.createElement('a');
p.appendChild(a);
a.href = 'javascript:void(0)';
a.onclick = hide_youtube_replies;
a.setAttribute('data-sub-text', community_data.hide_replies_text);
a.setAttribute('data-inner-text', community_data.show_replies_text);
a.innerText = community_data.hide_replies_text;
var div = document.createElement('div');
div.innerHTML = xhr.response.contentHtml;
body.appendChild(p);
body.appendChild(div);
}
} else {
body.removeChild(body.lastElementChild);
var p = document.createElement('p');
var a = document.createElement('a');
p.appendChild(a);
a.href = 'javascript:void(0)';
a.onclick = hide_youtube_replies;
a.setAttribute('data-sub-text', community_data.hide_replies_text);
a.setAttribute('data-inner-text', community_data.show_replies_text);
a.textContent = community_data.hide_replies_text;
var div = document.createElement('div');
div.innerHTML = response.contentHtml;
body.appendChild(p);
body.appendChild(div);
body.innerHTML = fallback;
}
},
onNon200: function (xhr) {
body.innerHTML = fallback;
},
onTimeout: function (xhr) {
console.warn('Pulling comments failed');
body.innerHTML = fallback;
}
});
}
xhr.ontimeout = function () {
console.log('Pulling comments failed.');
body.innerHTML = fallback;
}
xhr.send();
}

View File

@ -1,62 +1,102 @@
'use strict';
var video_data = JSON.parse(document.getElementById('video_data').textContent);
var video_data = JSON.parse(document.getElementById('video_data').innerHTML);
function get_playlist(plid, retries) {
if (retries == undefined) retries = 5;
if (retries <= 0) {
console.log('Failed to pull playlist');
return;
}
function get_playlist(plid) {
var plid_url;
if (plid.startsWith('RD')) {
plid_url = '/api/v1/mixes/' + plid +
var plid_url = '/api/v1/mixes/' + plid +
'?continuation=' + video_data.id +
'&format=html&hl=' + video_data.preferences.locale;
} else {
plid_url = '/api/v1/playlists/' + plid +
var plid_url = '/api/v1/playlists/' + plid +
'?index=' + video_data.index +
'&continuation' + video_data.id +
'&format=html&hl=' + video_data.preferences.locale;
}
helpers.xhr('GET', plid_url, {retries: 5, entity_name: 'playlist'}, {
on200: function (response) {
if (!response.nextVideo)
return;
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('GET', plid_url, true);
player.on('ended', function () {
var url = new URL('https://example.com/embed/' + response.nextVideo);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
if (xhr.response.nextVideo) {
player.on('ended', function () {
var url = new URL('https://example.com/embed/' + xhr.response.nextVideo);
url.searchParams.set('list', plid);
if (!plid.startsWith('RD'))
url.searchParams.set('index', response.index);
if (video_data.params.autoplay || video_data.params.continue_autoplay)
url.searchParams.set('autoplay', '1');
if (video_data.params.listen !== video_data.preferences.listen)
url.searchParams.set('listen', video_data.params.listen);
if (video_data.params.speed !== video_data.preferences.speed)
url.searchParams.set('speed', video_data.params.speed);
if (video_data.params.local !== video_data.preferences.local)
url.searchParams.set('local', video_data.params.local);
if (video_data.params.autoplay || video_data.params.continue_autoplay) {
url.searchParams.set('autoplay', '1');
}
location.assign(url.pathname + url.search);
});
if (video_data.params.listen !== video_data.preferences.listen) {
url.searchParams.set('listen', video_data.params.listen);
}
if (video_data.params.speed !== video_data.preferences.speed) {
url.searchParams.set('speed', video_data.params.speed);
}
if (video_data.params.local !== video_data.preferences.local) {
url.searchParams.set('local', video_data.params.local);
}
url.searchParams.set('list', plid);
if (!plid.startsWith('RD')) {
url.searchParams.set('index', xhr.response.index);
}
location.assign(url.pathname + url.search);
});
}
}
}
});
}
xhr.onerror = function () {
console.log('Pulling playlist failed... ' + retries + '/5');
setTimeout(function () { get_playlist(plid, retries - 1) }, 1000);
}
xhr.ontimeout = function () {
console.log('Pulling playlist failed... ' + retries + '/5');
get_playlist(plid, retries - 1);
}
xhr.send();
}
addEventListener('load', function (e) {
window.addEventListener('load', function (e) {
if (video_data.plid) {
get_playlist(video_data.plid);
} else if (video_data.video_series) {
player.on('ended', function () {
var url = new URL('https://example.com/embed/' + video_data.video_series.shift());
if (video_data.params.autoplay || video_data.params.continue_autoplay)
if (video_data.params.autoplay || video_data.params.continue_autoplay) {
url.searchParams.set('autoplay', '1');
if (video_data.params.listen !== video_data.preferences.listen)
}
if (video_data.params.listen !== video_data.preferences.listen) {
url.searchParams.set('listen', video_data.params.listen);
if (video_data.params.speed !== video_data.preferences.speed)
}
if (video_data.params.speed !== video_data.preferences.speed) {
url.searchParams.set('speed', video_data.params.speed);
if (video_data.params.local !== video_data.preferences.local)
}
if (video_data.params.local !== video_data.preferences.local) {
url.searchParams.set('local', video_data.params.local);
if (video_data.video_series.length !== 0)
url.searchParams.set('playlist', video_data.video_series.join(','));
}
if (video_data.video_series.length !== 0) {
url.searchParams.set('playlist', video_data.video_series.join(','))
}
location.assign(url.pathname + url.search);
});

3
assets/js/global.js Normal file
View File

@ -0,0 +1,3 @@
// Disable Web Workers. Fixes Video.js CSP violation (created by `new Worker(objURL)`):
// Refused to create a worker from 'blob:http://host/id' because it violates the following Content Security Policy directive: "worker-src 'self'".
window.Worker = undefined;

View File

@ -1,6 +1,8 @@
'use strict';
(function () {
var n2a = function (n) { return Array.prototype.slice.call(n); };
var video_player = document.getElementById('player_html5_api');
if (video_player) {
video_player.onmouseenter = function () { video_player['data-title'] = video_player['title']; video_player['title'] = ''; };
@ -9,141 +11,134 @@
}
// For dynamically inserted elements
addEventListener('click', function (e) {
if (!e || !e.target) return;
var t = e.target;
var handler_name = t.getAttribute('data-onclick');
document.addEventListener('click', function (e) {
if (!e || !e.target) { return; }
e = e.target;
var handler_name = e.getAttribute('data-onclick');
switch (handler_name) {
case 'jump_to_time':
e.preventDefault();
var time = t.getAttribute('data-jump-time');
var time = e.getAttribute('data-jump-time');
player.currentTime(time);
break;
case 'get_youtube_replies':
var load_more = t.getAttribute('data-load-more') !== null;
var load_replies = t.getAttribute('data-load-replies') !== null;
get_youtube_replies(t, load_more, load_replies);
var load_more = e.getAttribute('data-load-more') !== null;
get_youtube_replies(e, load_more);
break;
case 'toggle_parent':
e.preventDefault();
toggle_parent(t);
toggle_parent(e);
break;
default:
break;
}
});
document.querySelectorAll('[data-mouse="switch_classes"]').forEach(function (el) {
var classes = el.getAttribute('data-switch-classes').split(',');
var classOnEnter = classes[0];
var classOnLeave = classes[1];
function toggle_classes(toAdd, toRemove) {
el.classList.add(toAdd);
el.classList.remove(toRemove);
}
el.onmouseenter = function () { toggle_classes(classOnEnter, classOnLeave); };
el.onmouseleave = function () { toggle_classes(classOnLeave, classOnEnter); };
n2a(document.querySelectorAll('[data-mouse="switch_classes"]')).forEach(function (e) {
var classes = e.getAttribute('data-switch-classes').split(',');
var ec = classes[0];
var lc = classes[1];
var onoff = function (on, off) {
var cs = e.getAttribute('class');
cs = cs.split(off).join(on);
e.setAttribute('class', cs);
};
e.onmouseenter = function () { onoff(ec, lc); };
e.onmouseleave = function () { onoff(lc, ec); };
});
document.querySelectorAll('[data-onsubmit="return_false"]').forEach(function (el) {
el.onsubmit = function () { return false; };
n2a(document.querySelectorAll('[data-onsubmit="return_false"]')).forEach(function (e) {
e.onsubmit = function () { return false; };
});
document.querySelectorAll('[data-onclick="mark_watched"]').forEach(function (el) {
el.onclick = function () { mark_watched(el); };
n2a(document.querySelectorAll('[data-onclick="mark_watched"]')).forEach(function (e) {
e.onclick = function () { mark_watched(e); };
});
document.querySelectorAll('[data-onclick="mark_unwatched"]').forEach(function (el) {
el.onclick = function () { mark_unwatched(el); };
n2a(document.querySelectorAll('[data-onclick="mark_unwatched"]')).forEach(function (e) {
e.onclick = function () { mark_unwatched(e); };
});
document.querySelectorAll('[data-onclick="add_playlist_video"]').forEach(function (el) {
el.onclick = function () { add_playlist_video(el); };
n2a(document.querySelectorAll('[data-onclick="add_playlist_video"]')).forEach(function (e) {
e.onclick = function () { add_playlist_video(e); };
});
document.querySelectorAll('[data-onclick="add_playlist_item"]').forEach(function (el) {
el.onclick = function () { add_playlist_item(el); };
n2a(document.querySelectorAll('[data-onclick="add_playlist_item"]')).forEach(function (e) {
e.onclick = function () { add_playlist_item(e); };
});
document.querySelectorAll('[data-onclick="remove_playlist_item"]').forEach(function (el) {
el.onclick = function () { remove_playlist_item(el); };
n2a(document.querySelectorAll('[data-onclick="remove_playlist_item"]')).forEach(function (e) {
e.onclick = function () { remove_playlist_item(e); };
});
document.querySelectorAll('[data-onclick="revoke_token"]').forEach(function (el) {
el.onclick = function () { revoke_token(el); };
n2a(document.querySelectorAll('[data-onclick="revoke_token"]')).forEach(function (e) {
e.onclick = function () { revoke_token(e); };
});
document.querySelectorAll('[data-onclick="remove_subscription"]').forEach(function (el) {
el.onclick = function () { remove_subscription(el); };
n2a(document.querySelectorAll('[data-onclick="remove_subscription"]')).forEach(function (e) {
e.onclick = function () { remove_subscription(e); };
});
document.querySelectorAll('[data-onclick="notification_requestPermission"]').forEach(function (el) {
el.onclick = function () { Notification.requestPermission(); };
n2a(document.querySelectorAll('[data-onclick="notification_requestPermission"]')).forEach(function (e) {
e.onclick = function () { Notification.requestPermission(); };
});
document.querySelectorAll('[data-onrange="update_volume_value"]').forEach(function (el) {
function update_volume_value() {
document.getElementById('volume-value').textContent = el.value;
}
el.oninput = update_volume_value;
el.onchange = update_volume_value;
n2a(document.querySelectorAll('[data-onrange="update_volume_value"]')).forEach(function (e) {
var cb = function () { update_volume_value(e); }
e.oninput = cb;
e.onchange = cb;
});
function update_volume_value(element) {
document.getElementById('volume-value').innerText = element.value;
}
function revoke_token(target) {
var row = target.parentNode.parentNode.parentNode.parentNode.parentNode;
row.style.display = 'none';
var count = document.getElementById('count');
count.textContent--;
count.innerText = count.innerText - 1;
var referer = window.encodeURIComponent(document.location.href);
var url = '/token_ajax?action_revoke_token=1&redirect=false' +
'&referer=' + encodeURIComponent(location.href) +
'&referer=' + referer +
'&session=' + target.getAttribute('data-session');
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
var payload = 'csrf_token=' + target.parentNode.querySelector('input[name="csrf_token"]').value;
helpers.xhr('POST', url, {payload: payload}, {
onNon200: function (xhr) {
count.textContent++;
row.style.display = '';
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status != 200) {
count.innerText = parseInt(count.innerText) + 1;
row.style.display = '';
}
}
});
}
var csrf_token = target.parentNode.querySelector('input[name="csrf_token"]').value;
xhr.send('csrf_token=' + csrf_token);
}
function remove_subscription(target) {
var row = target.parentNode.parentNode.parentNode.parentNode.parentNode;
row.style.display = 'none';
var count = document.getElementById('count');
count.textContent--;
count.innerText = count.innerText - 1;
var referer = window.encodeURIComponent(document.location.href);
var url = '/subscription_ajax?action_remove_subscriptions=1&redirect=false' +
'&referer=' + encodeURIComponent(location.href) +
'&referer=' + referer +
'&c=' + target.getAttribute('data-ucid');
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
var payload = 'csrf_token=' + target.parentNode.querySelector('input[name="csrf_token"]').value;
helpers.xhr('POST', url, {payload: payload}, {
onNon200: function (xhr) {
count.textContent++;
row.style.display = '';
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status != 200) {
count.innerText = parseInt(count.innerText) + 1;
row.style.display = '';
}
}
});
}
var csrf_token = target.parentNode.querySelector('input[name="csrf_token"]').value;
xhr.send('csrf_token=' + csrf_token);
}
// Handle keypresses
addEventListener('keydown', function (event) {
// Ignore modifier keys
if (event.ctrlKey || event.metaKey) return;
// Ignore shortcuts if any text input is focused
let focused_tag = document.activeElement.tagName.toLowerCase();
const allowed = /^(button|checkbox|file|radio|submit)$/;
if (focused_tag === 'textarea') return;
if (focused_tag === 'input') {
let focused_type = document.activeElement.type.toLowerCase();
if (!focused_type.match(allowed)) return;
}
// Focus search bar on '/'
if (event.key === '/') {
document.getElementById('searchbox').focus();
event.preventDefault();
}
});
})();

View File

@ -1,30 +1,46 @@
'use strict';
var notification_data = JSON.parse(document.getElementById('notification_data').textContent);
/** Boolean meaning 'some tab have stream' */
const STORAGE_KEY_STREAM = 'stream';
/** Number of notifications. May be increased or reset */
const STORAGE_KEY_NOTIF_COUNT = 'notification_count';
var notification_data = JSON.parse(document.getElementById('notification_data').innerHTML);
var notifications, delivered;
var notifications_mock = { close: function () { } };
function get_subscriptions() {
helpers.xhr('GET', '/api/v1/auth/subscriptions?fields=authorId', {
retries: 5,
entity_name: 'subscriptions'
}, {
on200: create_notification_stream
});
function get_subscriptions(callback, retries) {
if (retries == undefined) retries = 5;
if (retries <= 0) {
return;
}
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('GET', '/api/v1/auth/subscriptions?fields=authorId', true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
subscriptions = xhr.response;
callback(subscriptions);
}
}
}
xhr.onerror = function () {
console.log('Pulling subscriptions failed... ' + retries + '/5');
setTimeout(function () { get_subscriptions(callback, retries - 1) }, 1000);
}
xhr.ontimeout = function () {
console.log('Pulling subscriptions failed... ' + retries + '/5');
get_subscriptions(callback, retries - 1);
}
xhr.send();
}
function create_notification_stream(subscriptions) {
// sse.js can't be replaced to EventSource in place as it lack support of payload and headers
// see https://developer.mozilla.org/en-US/docs/Web/API/EventSource/EventSource
notifications = new SSE(
'/api/v1/auth/notifications?fields=videoId,title,author,authorId,publishedText,published,authorThumbnails,liveNow', {
withCredentials: true,
payload: 'topics=' + subscriptions.map(function (subscription) { return subscription.authorId; }).join(','),
payload: 'topics=' + subscriptions.map(function (subscription) { return subscription.authorId }).join(','),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
delivered = [];
@ -32,100 +48,96 @@ function create_notification_stream(subscriptions) {
var start_time = Math.round(new Date() / 1000);
notifications.onmessage = function (event) {
if (!event.id) return;
if (!event.id) {
return;
}
var notification = JSON.parse(event.data);
console.info('Got notification:', notification);
console.log('Got notification:', notification);
// Ignore not actual and delivered notifications
if (start_time > notification.published || delivered.includes(notification.videoId)) return;
if (start_time < notification.published && !delivered.includes(notification.videoId)) {
if (Notification.permission === 'granted') {
var system_notification =
new Notification((notification.liveNow ? notification_data.live_now_text : notification_data.upload_text).replace('`x`', notification.author), {
body: notification.title,
icon: '/ggpht' + new URL(notification.authorThumbnails[2].url).pathname,
img: '/ggpht' + new URL(notification.authorThumbnails[4].url).pathname,
tag: notification.videoId
});
delivered.push(notification.videoId);
system_notification.onclick = function (event) {
window.open('/watch?v=' + event.currentTarget.tag, '_blank');
}
}
let notification_count = helpers.storage.get(STORAGE_KEY_NOTIF_COUNT) || 0;
notification_count++;
helpers.storage.set(STORAGE_KEY_NOTIF_COUNT, notification_count);
delivered.push(notification.videoId);
localStorage.setItem('notification_count', parseInt(localStorage.getItem('notification_count') || '0') + 1);
var notification_ticker = document.getElementById('notification_ticker');
update_ticker_count();
// permission for notifications handled on settings page. JS handler is in handlers.js
if (window.Notification && Notification.permission === 'granted') {
var notification_text = notification.liveNow ? notification_data.live_now_text : notification_data.upload_text;
notification_text = notification_text.replace('`x`', notification.author);
var system_notification = new Notification(notification_text, {
body: notification.title,
icon: '/ggpht' + new URL(notification.authorThumbnails[2].url).pathname,
img: '/ggpht' + new URL(notification.authorThumbnails[4].url).pathname
});
system_notification.onclick = function (e) {
open('/watch?v=' + notification.videoId, '_blank');
};
if (parseInt(localStorage.getItem('notification_count')) > 0) {
notification_ticker.innerHTML =
'<span id="notification_count">' + localStorage.getItem('notification_count') + '</span> <i class="icon ion-ios-notifications"></i>';
} else {
notification_ticker.innerHTML =
'<i class="icon ion-ios-notifications-outline"></i>';
}
}
};
notifications.addEventListener('error', function (e) {
console.warn('Something went wrong with notifications, trying to reconnect...');
notifications = notifications_mock;
setTimeout(get_subscriptions, 1000);
});
}
notifications.addEventListener('error', handle_notification_error);
notifications.stream();
}
function update_ticker_count() {
var notification_ticker = document.getElementById('notification_ticker');
function handle_notification_error(event) {
console.log('Something went wrong with notifications, trying to reconnect...');
notifications = { close: function () { } };
setTimeout(function () { get_subscriptions(create_notification_stream) }, 1000);
}
const notification_count = helpers.storage.get(STORAGE_KEY_STREAM);
if (notification_count > 0) {
notification_ticker.innerHTML =
'<span id="notification_count">' + notification_count + '</span> <i class="icon ion-ios-notifications"></i>';
window.addEventListener('load', function (e) {
localStorage.setItem('notification_count', document.getElementById('notification_count') ? document.getElementById('notification_count').innerText : '0');
if (localStorage.getItem('stream')) {
localStorage.removeItem('stream');
} else {
notification_ticker.innerHTML =
'<i class="icon ion-ios-notifications-outline"></i>';
setTimeout(function () {
if (!localStorage.getItem('stream')) {
notifications = { close: function () { } };
localStorage.setItem('stream', true);
get_subscriptions(create_notification_stream);
}
}, Math.random() * 1000 + 50);
}
}
function start_stream_if_needed() {
// random wait for other tabs set 'stream' flag
setTimeout(function () {
if (!helpers.storage.get(STORAGE_KEY_STREAM)) {
// if no one set 'stream', set it by yourself and start stream
helpers.storage.set(STORAGE_KEY_STREAM, true);
notifications = notifications_mock;
get_subscriptions();
window.addEventListener('storage', function (e) {
if (e.key === 'stream' && !e.newValue) {
if (notifications) {
localStorage.setItem('stream', true);
} else {
setTimeout(function () {
if (!localStorage.getItem('stream')) {
notifications = { close: function () { } };
localStorage.setItem('stream', true);
get_subscriptions(create_notification_stream);
}
}, Math.random() * 1000 + 50);
}
} else if (e.key === 'notification_count') {
var notification_ticker = document.getElementById('notification_ticker');
if (parseInt(e.newValue) > 0) {
notification_ticker.innerHTML =
'<span id="notification_count">' + e.newValue + '</span> <i class="icon ion-ios-notifications"></i>';
} else {
notification_ticker.innerHTML =
'<i class="icon ion-ios-notifications-outline"></i>';
}
}
}, Math.random() * 1000 + 50); // [0.050 .. 1.050) second
}
});
});
addEventListener('storage', function (e) {
if (e.key === STORAGE_KEY_NOTIF_COUNT)
update_ticker_count();
// if 'stream' key was removed
if (e.key === STORAGE_KEY_STREAM && !helpers.storage.get(STORAGE_KEY_STREAM)) {
if (notifications) {
// restore it if we have active stream
helpers.storage.set(STORAGE_KEY_STREAM, true);
} else {
start_stream_if_needed();
}
window.addEventListener('unload', function (e) {
if (notifications) {
localStorage.removeItem('stream');
}
});
addEventListener('load', function () {
var notification_count_el = document.getElementById('notification_count');
var notification_count = notification_count_el ? parseInt(notification_count_el.textContent) : 0;
helpers.storage.set(STORAGE_KEY_NOTIF_COUNT, notification_count);
if (helpers.storage.get(STORAGE_KEY_STREAM))
helpers.storage.remove(STORAGE_KEY_STREAM);
start_stream_if_needed();
});
addEventListener('unload', function () {
// let chance to other tabs to be a streamer via firing 'storage' event
if (notifications) helpers.storage.remove(STORAGE_KEY_STREAM);
});

View File

@ -1,6 +1,5 @@
'use strict';
var player_data = JSON.parse(document.getElementById('player_data').textContent);
var video_data = JSON.parse(document.getElementById('video_data').textContent);
var player_data = JSON.parse(document.getElementById('player_data').innerHTML);
var video_data = JSON.parse(document.getElementById('video_data').innerHTML);
var options = {
preload: 'auto',
@ -15,21 +14,13 @@ var options = {
'durationDisplay',
'progressControl',
'remainingTimeDisplay',
'Spacer',
'captionsButton',
'audioTrackButton',
'qualitySelector',
'playbackRateMenuButton',
'fullscreenToggle'
]
},
html5: {
preloadTextTracks: false,
vhs: {
overrideNative: true
}
}
};
}
if (player_data.aspect_ratio) {
options.aspectRatio = player_data.aspect_ratio;
@ -37,166 +28,62 @@ if (player_data.aspect_ratio) {
var embed_url = new URL(location);
embed_url.searchParams.delete('v');
var short_url = location.origin + '/' + video_data.id + embed_url.search;
short_url = location.origin + '/' + video_data.id + embed_url.search;
embed_url = location.origin + '/embed/' + video_data.id + embed_url.search;
var save_player_pos_key = 'save_player_pos';
var shareOptions = {
socials: ['fbFeed', 'tw', 'reddit', 'email'],
videojs.Vhs.xhr.beforeRequest = function(options) {
// set local if requested not videoplayback
if (!options.uri.includes('videoplayback')) {
if (!options.uri.includes('local=true'))
options.uri += '?local=true';
}
return options;
};
url: short_url,
title: player_data.title,
description: player_data.description,
image: player_data.thumbnail,
embedCode: "<iframe id='ivplayer' width='640' height='360' src='" + embed_url + "' style='border:none;'></iframe>"
}
var player = videojs('player', options);
player.on('error', function () {
if (video_data.params.quality === 'dash') return;
if (location.pathname.startsWith('/embed/')) {
player.overlay({
overlays: [{
start: 'loadstart',
content: '<h1><a rel="noopener" target="_blank" href="' + location.origin + '/watch?v=' + video_data.id + '">' + player_data.title + '</a></h1>',
end: 'playing',
align: 'top'
}, {
start: 'pause',
content: '<h1><a rel="noopener" target="_blank" href="' + location.origin + '/watch?v=' + video_data.id + '">' + player_data.title + '</a></h1>',
end: 'playing',
align: 'top'
}]
});
}
var localNotDisabled = (
!player.currentSrc().includes('local=true') && !video_data.local_disabled
);
var reloadMakesSense = (
player.error().code === MediaError.MEDIA_ERR_NETWORK ||
player.error().code === MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED
);
player.on('error', function (event) {
if (player.error().code === 2 || player.error().code === 4) {
setInterval(setTimeout(function (event) {
console.log('An error occured in the player, reloading...');
if (localNotDisabled) {
// add local=true to all current sources
player.src(player.currentSources().map(function (source) {
source.src += '&local=true';
return source;
}));
} else if (reloadMakesSense) {
setTimeout(function () {
console.warn('An error occurred in the player, reloading...');
// After load() all parameters are reset. Save them
var currentTime = player.currentTime();
var playbackRate = player.playbackRate();
var paused = player.paused();
player.load();
if (currentTime > 0.5) currentTime -= 0.5;
if (currentTime > 0.5) {
currentTime -= 0.5;
}
player.currentTime(currentTime);
player.playbackRate(playbackRate);
if (!paused) player.play();
}, 5000);
if (!paused) {
player.play();
}
}, 5000), 5000);
}
});
if (video_data.params.quality === 'dash') {
player.reloadSourceOnError({
errorInterval: 10
});
}
/**
* Function for add time argument to url
* @param {String} url
* @returns {URL} urlWithTimeArg
*/
function addCurrentTimeToURL(url) {
var urlUsed = new URL(url);
urlUsed.searchParams.delete('start');
var currentTime = Math.ceil(player.currentTime());
if (currentTime > 0)
urlUsed.searchParams.set('t', currentTime);
else if (urlUsed.searchParams.has('t'))
urlUsed.searchParams.delete('t');
return urlUsed;
}
var shareOptions = {
socials: ['fbFeed', 'tw', 'reddit', 'email'],
get url() {
return addCurrentTimeToURL(short_url);
},
title: player_data.title,
description: player_data.description,
image: player_data.thumbnail,
get embedCode() {
// Single quotes inside here required. HTML inserted as is into value attribute of input
return "<iframe id='ivplayer' width='640' height='360' src='" +
addCurrentTimeToURL(embed_url) + "' style='border:none;'></iframe>";
}
};
if (location.pathname.startsWith('/embed/')) {
var overlay_content = '<h1><a rel="noopener" target="_blank" href="' + location.origin + '/watch?v=' + video_data.id + '">' + player_data.title + '</a></h1>';
player.overlay({
overlays: [
{ start: 'loadstart', content: overlay_content, end: 'playing', align: 'top'},
{ start: 'pause', content: overlay_content, end: 'playing', align: 'top'}
]
});
}
// Detect mobile users and initialize mobileUi for better UX
// Detection code taken from https://stackoverflow.com/a/20293441
function isMobile() {
try{ document.createEvent('TouchEvent'); return true; }
catch(e){ return false; }
}
if (isMobile()) {
player.mobileUi({ touchControls: { seekSeconds: 5 * player.playbackRate() } });
var buttons = ['playToggle', 'volumePanel', 'captionsButton'];
if (!video_data.params.listen && video_data.params.quality === 'dash') buttons.push('audioTrackButton');
if (video_data.params.listen || video_data.params.quality !== 'dash') buttons.push('qualitySelector');
// Create new control bar object for operation buttons
const ControlBar = videojs.getComponent('controlBar');
let operations_bar = new ControlBar(player, {
children: [],
playbackRates: [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0]
});
buttons.slice(1).forEach(function (child) {operations_bar.addChild(child);});
// Remove operation buttons from primary control bar
var primary_control_bar = player.getChild('controlBar');
buttons.forEach(function (child) {primary_control_bar.removeChild(child);});
var operations_bar_element = operations_bar.el();
operations_bar_element.classList.add('mobile-operations-bar');
player.addChild(operations_bar);
// Playback menu doesn't work when it's initialized outside of the primary control bar
var playback_element = document.getElementsByClassName('vjs-playback-rate')[0];
operations_bar_element.append(playback_element);
// The share and http source selector element can't be fetched till the players ready.
player.one('playing', function () {
var share_element = document.getElementsByClassName('vjs-share-control')[0];
operations_bar_element.append(share_element);
if (!video_data.params.listen && video_data.params.quality === 'dash') {
var http_source_selector = document.getElementsByClassName('vjs-http-source-selector vjs-menu-button')[0];
operations_bar_element.append(http_source_selector);
}
});
}
// Enable VR video support
if (!video_data.params.listen && video_data.vr && video_data.params.vr_mode) {
player.crossOrigin('anonymous');
switch (video_data.projection_type) {
case 'EQUIRECTANGULAR':
player.vr({projection: 'equirectangular'});
default: // Should only be 'MESH' but we'll use this as a fallback.
player.vr({projection: 'EAC'});
}
}
// Add markers
if (video_data.params.video_start > 0 || video_data.params.video_end > 0) {
var markers = [{ time: video_data.params.video_start, text: 'Start' }];
@ -209,8 +96,13 @@ if (video_data.params.video_start > 0 || video_data.params.video_end > 0) {
player.markers({
onMarkerReached: function (marker) {
if (marker.text === 'End')
player.loop() ? player.markers.prev('Start') : player.pause();
if (marker.text === 'End') {
if (player.loop()) {
player.markers.prev('Start');
} else {
player.pause();
}
}
},
markers: markers
});
@ -221,76 +113,9 @@ if (video_data.params.video_start > 0 || video_data.params.video_end > 0) {
player.volume(video_data.params.volume / 100);
player.playbackRate(video_data.params.speed);
/**
* Method for getting the contents of a cookie
*
* @param {String} name Name of cookie
* @returns {String|null} cookieValue
*/
function getCookieValue(name) {
var cookiePrefix = name + '=';
var matchedCookie = document.cookie.split(';').find(function (item) {return item.includes(cookiePrefix);});
if (matchedCookie)
return matchedCookie.replace(cookiePrefix, '');
return null;
}
/**
* Method for updating the 'PREFS' cookie (or creating it if missing)
*
* @param {number} newVolume New volume defined (null if unchanged)
* @param {number} newSpeed New speed defined (null if unchanged)
*/
function updateCookie(newVolume, newSpeed) {
var volumeValue = newVolume !== null ? newVolume : video_data.params.volume;
var speedValue = newSpeed !== null ? newSpeed : video_data.params.speed;
var cookieValue = getCookieValue('PREFS');
var cookieData;
if (cookieValue !== null) {
var cookieJson = JSON.parse(decodeURIComponent(cookieValue));
cookieJson.volume = volumeValue;
cookieJson.speed = speedValue;
cookieData = encodeURIComponent(JSON.stringify(cookieJson));
} else {
cookieData = encodeURIComponent(JSON.stringify({ 'volume': volumeValue, 'speed': speedValue }));
}
// Set expiration in 2 year
var date = new Date();
date.setFullYear(date.getFullYear() + 2);
var ipRegex = /^((\d+\.){3}\d+|[A-Fa-f0-9]*:[A-Fa-f0-9:]*:[A-Fa-f0-9:]+)$/;
var domainUsed = location.hostname;
// Fix for a bug in FF where the leading dot in the FQDN is not ignored
if (domainUsed.charAt(0) !== '.' && !ipRegex.test(domainUsed) && domainUsed !== 'localhost')
domainUsed = '.' + location.hostname;
var secure = location.protocol.startsWith("https") ? " Secure;" : "";
document.cookie = 'PREFS=' + cookieData + '; SameSite=Lax; path=/; domain=' +
domainUsed + '; expires=' + date.toGMTString() + ';' + secure;
video_data.params.volume = volumeValue;
video_data.params.speed = speedValue;
}
player.on('ratechange', function () {
updateCookie(null, player.playbackRate());
if (isMobile()) {
player.mobileUi({ touchControls: { seekSeconds: 5 * player.playbackRate() } });
}
});
player.on('volumechange', function () {
updateCookie(Math.ceil(player.volume() * 100), null);
});
player.on('waiting', function () {
if (player.playbackRate() > 1 && player.liveTracker.isLive() && player.liveTracker.atLiveEdge()) {
console.info('Player has caught up to source, resetting playbackRate');
console.log('Player has caught up to source, resetting playbackRate.')
player.playbackRate(1);
}
});
@ -299,39 +124,19 @@ if (video_data.premiere_timestamp && Math.round(new Date() / 1000) < video_data.
player.getChild('bigPlayButton').hide();
}
if (video_data.params.save_player_pos) {
const url = new URL(location);
const hasTimeParam = url.searchParams.has('t');
const rememberedTime = get_video_time();
let lastUpdated = 0;
if(!hasTimeParam) set_seconds_after_start(rememberedTime);
player.on('timeupdate', function () {
const raw = player.currentTime();
const time = Math.floor(raw);
if(lastUpdated !== time && raw <= video_data.length_seconds - 15) {
save_video_time(time);
lastUpdated = time;
}
});
}
else remove_all_video_times();
if (video_data.params.autoplay) {
var bpb = player.getChild('bigPlayButton');
bpb.hide();
player.ready(function () {
new Promise(function (resolve, reject) {
setTimeout(function () {resolve(1);}, 1);
setTimeout(() => resolve(1), 1);
}).then(function (result) {
var promise = player.play();
if (promise !== undefined) {
promise.then(function () {
}).catch(function (error) {
promise.then(_ => {
}).catch(error => {
bpb.show();
});
}
@ -341,48 +146,38 @@ if (video_data.params.autoplay) {
if (!video_data.params.listen && video_data.params.quality === 'dash') {
player.httpSourceSelector();
if (video_data.params.quality_dash !== 'auto') {
player.ready(function () {
player.on('loadedmetadata', function () {
const qualityLevels = Array.from(player.qualityLevels()).sort(function (a, b) {return a.height - b.height;});
let targetQualityLevel;
switch (video_data.params.quality_dash) {
case 'best':
targetQualityLevel = qualityLevels.length - 1;
break;
case 'worst':
targetQualityLevel = 0;
break;
default:
const targetHeight = parseInt(video_data.params.quality_dash);
for (let i = 0; i < qualityLevels.length; i++) {
if (qualityLevels[i].height <= targetHeight)
targetQualityLevel = i;
else
break;
}
}
qualityLevels.forEach(function (level, index) {
level.enabled = (index === targetQualityLevel);
});
});
});
}
}
player.vttThumbnails({
src: '/api/v1/storyboards/' + video_data.id + '?height=90',
showTimestamp: true
src: location.origin + '/api/v1/storyboards/' + video_data.id + '?height=90'
});
// Enable annotations
if (!video_data.params.listen && video_data.params.annotations) {
addEventListener('load', function (e) {
addEventListener('__ar_annotation_click', function (e) {
const url = e.detail.url,
target = e.detail.target,
seconds = e.detail.seconds;
window.addEventListener('load', function (e) {
var video_container = document.getElementById('player');
let xhr = new XMLHttpRequest();
xhr.responseType = 'text';
xhr.timeout = 60000;
xhr.open('GET', '/api/v1/annotations/' + video_data.id, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
videojs.registerPlugin('youtubeAnnotationsPlugin', youtubeAnnotationsPlugin);
if (!player.paused()) {
player.youtubeAnnotationsPlugin({ annotationXml: xhr.response, videoContainer: video_container });
} else {
player.one('play', function (event) {
player.youtubeAnnotationsPlugin({ annotationXml: xhr.response, videoContainer: video_container });
});
}
}
}
}
window.addEventListener('__ar_annotation_click', e => {
const { url, target, seconds } = e.detail;
var path = new URL(url);
if (path.href.startsWith('https://www.youtube.com/watch?') && seconds) {
@ -392,104 +187,75 @@ if (!video_data.params.listen && video_data.params.annotations) {
path = path.pathname + path.search;
if (target === 'current') {
location.href = path;
window.location.href = path;
} else if (target === 'new') {
open(path, '_blank');
}
});
helpers.xhr('GET', '/api/v1/annotations/' + video_data.id, {
responseType: 'text',
timeout: 60000
}, {
on200: function (response) {
var video_container = document.getElementById('player');
videojs.registerPlugin('youtubeAnnotationsPlugin', youtubeAnnotationsPlugin);
if (player.paused()) {
player.one('play', function (event) {
player.youtubeAnnotationsPlugin({ annotationXml: response, videoContainer: video_container });
});
} else {
player.youtubeAnnotationsPlugin({ annotationXml: response, videoContainer: video_container });
}
window.open(path, '_blank');
}
});
xhr.send();
});
}
function change_volume(delta) {
function increase_volume(delta) {
const curVolume = player.volume();
let newVolume = curVolume + delta;
newVolume = helpers.clamp(newVolume, 0, 1);
if (newVolume > 1) {
newVolume = 1;
} else if (newVolume < 0) {
newVolume = 0;
}
player.volume(newVolume);
}
function toggle_muted() {
player.muted(!player.muted());
const isMuted = player.muted();
player.muted(!isMuted);
}
function skip_seconds(delta) {
const duration = player.duration();
const curTime = player.currentTime();
let newTime = curTime + delta;
newTime = helpers.clamp(newTime, 0, duration);
if (newTime > duration) {
newTime = duration;
} else if (newTime < 0) {
newTime = 0;
}
player.currentTime(newTime);
}
function set_seconds_after_start(delta) {
const start = video_data.params.video_start;
player.currentTime(start + delta);
}
function save_video_time(seconds) {
const all_video_times = get_all_video_times();
all_video_times[video_data.id] = seconds;
helpers.storage.set(save_player_pos_key, all_video_times);
}
function get_video_time() {
return get_all_video_times()[video_data.id] || 0;
}
function get_all_video_times() {
return helpers.storage.get(save_player_pos_key) || {};
}
function remove_all_video_times() {
helpers.storage.remove(save_player_pos_key);
}
function set_time_percent(percent) {
const duration = player.duration();
const newTime = duration * (percent / 100);
player.currentTime(newTime);
}
function play() { player.play(); }
function pause() { player.pause(); }
function stop() { player.pause(); player.currentTime(0); }
function toggle_play() { player.paused() ? play() : pause(); }
function toggle_play() {
if (player.paused()) {
player.play();
} else {
player.pause();
}
}
const toggle_captions = (function () {
let toggledTrack = null;
function bindChange(onOrOff) {
player.textTracks()[onOrOff]('change', function (e) {
toggledTrack = null;
});
}
const onChange = function (e) {
toggledTrack = null;
};
const bindChange = function (onOrOff) {
player.textTracks()[onOrOff]('change', onChange);
};
// Wrapper function to ignore our own emitted events and only listen
// to events emitted by Video.js on click on the captions menu items.
function setMode(track, mode) {
const setMode = function (track, mode) {
bindChange('off');
track.mode = mode;
setTimeout(function () {
window.setTimeout(function () {
bindChange('on');
}, 0);
}
};
bindChange('on');
return function () {
if (toggledTrack !== null) {
@ -509,7 +275,9 @@ const toggle_captions = (function () {
const tracks = player.textTracks();
for (let i = 0; i < tracks.length; i++) {
const track = tracks[i];
if (track.kind !== 'captions') continue;
if (track.kind !== 'captions') {
continue;
}
if (fallbackCaptionsTrack === null) {
fallbackCaptionsTrack = track;
@ -530,18 +298,26 @@ const toggle_captions = (function () {
})();
function toggle_fullscreen() {
player.isFullscreen() ? player.exitFullscreen() : player.requestFullscreen();
if (player.isFullscreen()) {
player.exitFullscreen();
} else {
player.requestFullscreen();
}
}
function increase_playback_rate(steps) {
const maxIndex = options.playbackRates.length - 1;
const curIndex = options.playbackRates.indexOf(player.playbackRate());
let newIndex = curIndex + steps;
newIndex = helpers.clamp(newIndex, 0, maxIndex);
if (newIndex > maxIndex) {
newIndex = maxIndex;
} else if (newIndex < 0) {
newIndex = 0;
}
player.playbackRate(options.playbackRates[newIndex]);
}
addEventListener('keydown', function (e) {
window.addEventListener('keydown', e => {
if (e.target.tagName.toLowerCase() === 'input') {
// Ignore input when focus is on certain elements, e.g. form fields.
return;
@ -565,19 +341,18 @@ addEventListener('keydown', function (e) {
switch (decoratedKey) {
case ' ':
case 'k':
case 'MediaPlayPause':
action = toggle_play;
break;
case 'MediaPlay': action = play; break;
case 'MediaPause': action = pause; break;
case 'MediaStop': action = stop; break;
case 'ArrowUp':
if (isPlayerFocused) action = change_volume.bind(this, 0.1);
if (isPlayerFocused) {
action = increase_volume.bind(this, 0.1);
}
break;
case 'ArrowDown':
if (isPlayerFocused) action = change_volume.bind(this, -0.1);
if (isPlayerFocused) {
action = increase_volume.bind(this, -0.1);
}
break;
case 'm':
@ -585,18 +360,16 @@ addEventListener('keydown', function (e) {
break;
case 'ArrowRight':
case 'MediaFastForward':
action = skip_seconds.bind(this, 5 * player.playbackRate());
action = skip_seconds.bind(this, 5);
break;
case 'ArrowLeft':
case 'MediaTrackPrevious':
action = skip_seconds.bind(this, -5 * player.playbackRate());
action = skip_seconds.bind(this, -5);
break;
case 'l':
action = skip_seconds.bind(this, 10 * player.playbackRate());
action = skip_seconds.bind(this, 10);
break;
case 'j':
action = skip_seconds.bind(this, -10 * player.playbackRate());
action = skip_seconds.bind(this, -10);
break;
case '0':
@ -609,33 +382,37 @@ addEventListener('keydown', function (e) {
case '7':
case '8':
case '9':
// Ignore numpad numbers
if (code > 57) break;
const percent = (code - 48) * 10;
action = set_time_percent.bind(this, percent);
break;
case 'c': action = toggle_captions; break;
case 'f': action = toggle_fullscreen; break;
case 'c':
action = toggle_captions;
break;
case 'f':
action = toggle_fullscreen;
break;
case 'N':
case 'MediaTrackNext':
action = next_video;
break;
case 'P':
case 'MediaTrackPrevious':
// TODO: Add support to play back previous video.
break;
// TODO: More precise step. Now FPS is taken equal to 29.97
// Common FPS: https://forum.videohelp.com/threads/81868#post323588
// Possible solution is new HTMLVideoElement.requestVideoFrameCallback() https://wicg.github.io/video-rvfc/
case ',': action = function () { pause(); skip_seconds(-1/29.97); }; break;
case '.': action = function () { pause(); skip_seconds( 1/29.97); }; break;
case '.':
// TODO: Add support for next-frame-stepping.
break;
case ',':
// TODO: Add support for previous-frame-stepping.
break;
case '>': action = increase_playback_rate.bind(this, 1); break;
case '<': action = increase_playback_rate.bind(this, -1); break;
case '>':
action = increase_playback_rate.bind(this, 1);
break;
case '<':
action = increase_playback_rate.bind(this, -1);
break;
default:
console.info('Unhandled key down event: %s:', decoratedKey, e);
@ -651,77 +428,47 @@ addEventListener('keydown', function (e) {
// Add support for controlling the player volume by scrolling over it. Adapted from
// https://github.com/ctd1500/videojs-hotkeys/blob/bb4a158b2e214ccab87c2e7b95f42bc45c6bfd87/videojs.hotkeys.js#L292-L328
(function () {
const volumeStep = 0.05;
const enableVolumeScroll = true;
const enableHoverScroll = true;
const doc = document;
const pEl = document.getElementById('player');
var volumeHover = false;
var volumeSelector = pEl.querySelector('.vjs-volume-menu-button') || pEl.querySelector('.vjs-volume-panel');
if (volumeSelector !== null) {
if (volumeSelector != null) {
volumeSelector.onmouseover = function () { volumeHover = true; };
volumeSelector.onmouseout = function () { volumeHover = false; };
}
function mouseScroll(event) {
var mouseScroll = function mouseScroll(event) {
var activeEl = doc.activeElement;
if (enableHoverScroll) {
// If we leave this undefined then it can match non-existent elements below
activeEl = 0;
}
// When controls are disabled, hotkeys will be disabled as well
if (!player.controls() || !volumeHover) return;
if (player.controls()) {
if (volumeHover) {
if (enableVolumeScroll) {
event = window.event || event;
var delta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)));
event.preventDefault();
event.preventDefault();
var wheelMove = event.wheelDelta || -event.detail;
var volumeSign = Math.sign(wheelMove);
change_volume(volumeSign * 0.05); // decrease/increase by 5%
}
if (delta == 1) {
increase_volume(volumeStep);
} else if (delta == -1) {
increase_volume(-volumeStep);
}
}
}
}
};
player.on('mousewheel', mouseScroll);
player.on('DOMMouseScroll', mouseScroll);
player.on("DOMMouseScroll", mouseScroll);
}());
// Since videojs-share can sometimes be blocked, we defer it until last
if (player.share) player.share(shareOptions);
// show the preferred caption by default
if (player_data.preferred_caption_found) {
player.ready(function () {
if (!video_data.params.listen && video_data.params.quality === 'dash') {
// play.textTracks()[0] on DASH mode is showing some debug messages
player.textTracks()[1].mode = 'showing';
} else {
player.textTracks()[0].mode = 'showing';
}
});
}
// Safari audio double duration fix
if (navigator.vendor === 'Apple Computer, Inc.' && video_data.params.listen) {
player.on('loadedmetadata', function () {
player.on('timeupdate', function () {
if (player.remainingTime() < player.duration() / 2 && player.remainingTime() >= 2) {
player.currentTime(player.duration() - 1);
}
});
});
}
// Watch on Invidious link
if (location.pathname.startsWith('/embed/')) {
const Button = videojs.getComponent('Button');
let watch_on_invidious_button = new Button(player);
// Create hyperlink for current instance
var redirect_element = document.createElement('a');
redirect_element.setAttribute('href', location.pathname.replace('/embed/', '/watch?v='));
redirect_element.appendChild(document.createTextNode('Invidious'));
watch_on_invidious_button.el().appendChild(redirect_element);
watch_on_invidious_button.addClass('watch-on-invidious');
var cb = player.getChild('ControlBar');
cb.addChild(watch_on_invidious_button);
}
addEventListener('DOMContentLoaded', function () {
// Save time during redirection on another instance
const changeInstanceLink = document.querySelector('#watch-on-another-invidious-instance > a');
if (changeInstanceLink) changeInstanceLink.addEventListener('click', function () {
changeInstanceLink.href = addCurrentTimeToURL(changeInstanceLink.href);
});
});
player.share(shareOptions);

View File

@ -1,6 +1,4 @@
'use strict';
var playlist_data = JSON.parse(document.getElementById('playlist_data').textContent);
var payload = 'csrf_token=' + playlist_data.csrf_token;
var playlist_data = JSON.parse(document.getElementById('playlist_data').innerHTML);
function add_playlist_video(target) {
var select = target.parentNode.children[0].children[1];
@ -9,12 +7,21 @@ function add_playlist_video(target) {
var url = '/playlist_ajax?action_add_video=1&redirect=false' +
'&video_id=' + target.getAttribute('data-id') +
'&playlist_id=' + option.getAttribute('data-plid');
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
helpers.xhr('POST', url, {payload: payload}, {
on200: function (response) {
option.textContent = '✓' + option.textContent;
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
option.innerText = '✓' + option.innerText;
}
}
});
}
xhr.send('csrf_token=' + playlist_data.csrf_token);
}
function add_playlist_item(target) {
@ -24,12 +31,21 @@ function add_playlist_item(target) {
var url = '/playlist_ajax?action_add_video=1&redirect=false' +
'&video_id=' + target.getAttribute('data-id') +
'&playlist_id=' + target.getAttribute('data-plid');
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
helpers.xhr('POST', url, {payload: payload}, {
onNon200: function (xhr) {
tile.style.display = '';
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status != 200) {
tile.style.display = '';
}
}
});
}
xhr.send('csrf_token=' + playlist_data.csrf_token);
}
function remove_playlist_item(target) {
@ -39,10 +55,19 @@ function remove_playlist_item(target) {
var url = '/playlist_ajax?action_remove_video=1&redirect=false' +
'&set_video_id=' + target.getAttribute('data-index') +
'&playlist_id=' + target.getAttribute('data-plid');
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
helpers.xhr('POST', url, {payload: payload}, {
onNon200: function (xhr) {
tile.style.display = '';
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status != 200) {
tile.style.display = '';
}
}
});
}
}
xhr.send('csrf_token=' + playlist_data.csrf_token);
}

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,7 @@
'use strict';
var subscribe_data = JSON.parse(document.getElementById('subscribe_data').textContent);
var payload = 'csrf_token=' + subscribe_data.csrf_token;
var subscribe_data = JSON.parse(document.getElementById('subscribe_data').innerHTML);
var subscribe_button = document.getElementById('subscribe');
subscribe_button.parentNode.action = 'javascript:void(0)';
subscribe_button.parentNode['action'] = 'javascript:void(0)';
if (subscribe_button.getAttribute('data-type') === 'subscribe') {
subscribe_button.onclick = subscribe;
@ -11,34 +9,82 @@ if (subscribe_button.getAttribute('data-type') === 'subscribe') {
subscribe_button.onclick = unsubscribe;
}
function subscribe() {
function subscribe(retries = 5) {
if (retries <= 0) {
console.log('Failed to subscribe.');
return;
}
var url = '/subscription_ajax?action_create_subscription_to_channel=1&redirect=false' +
'&c=' + subscribe_data.ucid;
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
var fallback = subscribe_button.innerHTML;
subscribe_button.onclick = unsubscribe;
subscribe_button.innerHTML = '<b>' + subscribe_data.unsubscribe_text + ' | ' + subscribe_data.sub_count_text + '</b>';
var url = '/subscription_ajax?action_create_subscription_to_channel=1&redirect=false' +
'&c=' + subscribe_data.ucid;
helpers.xhr('POST', url, {payload: payload, retries: 5, entity_name: 'subscribe request'}, {
onNon200: function (xhr) {
subscribe_button.onclick = subscribe;
subscribe_button.innerHTML = fallback;
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status != 200) {
subscribe_button.onclick = subscribe;
subscribe_button.innerHTML = fallback;
}
}
});
}
xhr.onerror = function () {
console.log('Subscribing failed... ' + retries + '/5');
setTimeout(function () { subscribe(retries - 1) }, 1000);
}
xhr.ontimeout = function () {
console.log('Subscribing failed... ' + retries + '/5');
subscribe(retries - 1);
}
xhr.send('csrf_token=' + subscribe_data.csrf_token);
}
function unsubscribe() {
function unsubscribe(retries = 5) {
if (retries <= 0) {
console.log('Failed to subscribe');
return;
}
var url = '/subscription_ajax?action_remove_subscriptions=1&redirect=false' +
'&c=' + subscribe_data.ucid;
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
var fallback = subscribe_button.innerHTML;
subscribe_button.onclick = subscribe;
subscribe_button.innerHTML = '<b>' + subscribe_data.subscribe_text + ' | ' + subscribe_data.sub_count_text + '</b>';
var url = '/subscription_ajax?action_remove_subscriptions=1&redirect=false' +
'&c=' + subscribe_data.ucid;
helpers.xhr('POST', url, {payload: payload, retries: 5, entity_name: 'unsubscribe request'}, {
onNon200: function (xhr) {
subscribe_button.onclick = unsubscribe;
subscribe_button.innerHTML = fallback;
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status != 200) {
subscribe_button.onclick = unsubscribe;
subscribe_button.innerHTML = fallback;
}
}
});
}
xhr.onerror = function () {
console.log('Unsubscribing failed... ' + retries + '/5');
setTimeout(function () { unsubscribe(retries - 1) }, 1000);
}
xhr.ontimeout = function () {
console.log('Unsubscribing failed... ' + retries + '/5');
unsubscribe(retries - 1);
}
xhr.send('csrf_token=' + subscribe_data.csrf_token);
}

View File

@ -1,44 +1,79 @@
'use strict';
var toggle_theme = document.getElementById('toggle_theme');
toggle_theme.href = 'javascript:void(0)';
toggle_theme.href = 'javascript:void(0);';
const STORAGE_KEY_THEME = 'dark_mode';
const THEME_DARK = 'dark';
const THEME_LIGHT = 'light';
// TODO: theme state controlled by system
toggle_theme.addEventListener('click', function () {
const isDarkTheme = helpers.storage.get(STORAGE_KEY_THEME) === THEME_DARK;
const newTheme = isDarkTheme ? THEME_LIGHT : THEME_DARK;
setTheme(newTheme);
helpers.storage.set(STORAGE_KEY_THEME, newTheme);
helpers.xhr('GET', '/toggle_theme?redirect=false', {}, {});
var dark_mode = document.getElementById('dark_theme').media === 'none';
var url = '/toggle_theme?redirect=false';
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('GET', url, true);
set_mode(dark_mode);
window.localStorage.setItem('dark_mode', dark_mode ? 'dark' : 'light');
xhr.send();
});
/** @param {THEME_DARK|THEME_LIGHT} theme */
function setTheme(theme) {
// By default body element has .no-theme class that uses OS theme via CSS @media rules
// It rewrites using hard className below
if (theme === THEME_DARK) {
toggle_theme.children[0].className = 'icon ion-ios-sunny';
document.body.className = 'dark-theme';
window.addEventListener('storage', function (e) {
if (e.key === 'dark_mode') {
update_mode(e.newValue);
}
});
window.addEventListener('load', function () {
window.localStorage.setItem('dark_mode', document.getElementById('dark_mode_pref').textContent);
// Update localStorage if dark mode preference changed on preferences page
update_mode(window.localStorage.dark_mode);
});
var darkScheme = window.matchMedia('(prefers-color-scheme: dark)');
var lightScheme = window.matchMedia('(prefers-color-scheme: light)');
darkScheme.addListener(scheme_switch);
lightScheme.addListener(scheme_switch);
function scheme_switch (e) {
// ignore this method if we have a preference set
if (localStorage.getItem('dark_mode')) {
return;
}
if (e.matches) {
if (e.media.includes("dark")) {
set_mode(true);
} else if (e.media.includes("light")) {
set_mode(false);
}
}
}
function set_mode (bool) {
document.getElementById('dark_theme').media = !bool ? 'none' : '';
document.getElementById('light_theme').media = bool ? 'none' : '';
if (bool) {
toggle_theme.children[0].setAttribute('class', 'icon ion-ios-sunny');
} else {
toggle_theme.children[0].className = 'icon ion-ios-moon';
document.body.className = 'light-theme';
toggle_theme.children[0].setAttribute('class', 'icon ion-ios-moon');
}
}
// Handles theme change event caused by other tab
addEventListener('storage', function (e) {
if (e.key === STORAGE_KEY_THEME)
setTheme(helpers.storage.get(STORAGE_KEY_THEME));
});
// Set theme from preferences on page load
addEventListener('DOMContentLoaded', function () {
const prefTheme = document.getElementById('dark_mode_pref').textContent;
if (prefTheme) {
setTheme(prefTheme);
helpers.storage.set(STORAGE_KEY_THEME, prefTheme);
function update_mode (mode) {
if (mode === 'true' /* for backwards compatibility */ || mode === 'dark') {
// If preference for dark mode indicated
set_mode(true);
}
});
else if (mode === 'false' /* for backwards compaibility */ || mode === 'light') {
// If preference for light mode indicated
set_mode(false);
}
else if (document.getElementById('dark_mode_pref').textContent === '' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
// If no preference indicated here and no preference indicated on the preferences page (backend), but the browser tells us that the operating system has a dark theme
set_mode(true);
}
// else do nothing, falling back to the mode defined by the `dark_mode` preference on the preferences page (backend)
}

21
assets/js/video.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
/*! @name videojs-contrib-quality-levels @version 2.0.9 @license Apache-2.0 */
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("video.js"),require("global/document")):"function"==typeof define&&define.amd?define(["video.js","global/document"],t):e.videojsContribQualityLevels=t(e.videojs,e.document)}(this,function(e,t){"use strict";function n(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}e=e&&e.hasOwnProperty("default")?e.default:e,t=t&&t.hasOwnProperty("default")?t.default:t;var r=function(r){var i,l;function o(){var i,l=n(n(i=r.call(this)||this));if(e.browser.IS_IE8)for(var s in l=t.createElement("custom"),o.prototype)"constructor"!==s&&(l[s]=o.prototype[s]);return l.levels_=[],l.selectedIndex_=-1,Object.defineProperty(l,"selectedIndex",{get:function(){return l.selectedIndex_}}),Object.defineProperty(l,"length",{get:function(){return l.levels_.length}}),l||n(i)}l=r,(i=o).prototype=Object.create(l.prototype),i.prototype.constructor=i,i.__proto__=l;var s=o.prototype;return s.addQualityLevel=function(n){var r=this.getQualityLevelById(n.id);if(r)return r;var i=this.levels_.length;return r=new function n(r){var i=this;if(e.browser.IS_IE8)for(var l in i=t.createElement("custom"),n.prototype)"constructor"!==l&&(i[l]=n.prototype[l]);return i.id=r.id,i.label=i.id,i.width=r.width,i.height=r.height,i.bitrate=r.bandwidth,i.enabled_=r.enabled,Object.defineProperty(i,"enabled",{get:function(){return i.enabled_()},set:function(e){i.enabled_(e)}}),i}(n),""+i in this||Object.defineProperty(this,i,{get:function(){return this.levels_[i]}}),this.levels_.push(r),this.trigger({qualityLevel:r,type:"addqualitylevel"}),r},s.removeQualityLevel=function(e){for(var t=null,n=0,r=this.length;n<r;n++)if(this[n]===e){t=this.levels_.splice(n,1)[0],this.selectedIndex_===n?this.selectedIndex_=-1:this.selectedIndex_>n&&this.selectedIndex_--;break}return t&&this.trigger({qualityLevel:e,type:"removequalitylevel"}),t},s.getQualityLevelById=function(e){for(var t=0,n=this.length;t<n;t++){var r=this[t];if(r.id===e)return r}return null},s.dispose=function(){this.selectedIndex_=-1,this.levels_.length=0},o}(e.EventTarget);for(var i in r.prototype.allowedEvents_={change:"change",addqualitylevel:"addqualitylevel",removequalitylevel:"removequalitylevel"},r.prototype.allowedEvents_)r.prototype["on"+i]=null;var l=function(t){return n=this,e.mergeOptions({},t),i=n.qualityLevels,l=new r,n.on("dispose",function e(){l.dispose(),n.qualityLevels=i,n.off("dispose",e)}),n.qualityLevels=function(){return l},n.qualityLevels.VERSION="2.0.9",l;var n,i,l};return(e.registerPlugin||e.plugin)("qualityLevels",l),l.VERSION="2.0.9",l});

View File

@ -0,0 +1,7 @@
/**
* videojs-http-source-selector
* @version 1.1.6
* @copyright 2019 Justin Fujita <Justin@pivotshare.com>
* @license MIT
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("video.js")):"function"==typeof define&&define.amd?define(["video.js"],t):(e=e||self)["videojs-http-source-selector"]=t(e.videojs)}(this,function(r){"use strict";function o(e,t){e.prototype=Object.create(t.prototype),(e.prototype.constructor=e).__proto__=t}function s(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}var e=(r=r&&r.hasOwnProperty("default")?r.default:r).getComponent("MenuItem"),t=r.getComponent("Component"),a=function(n){function e(e,t){return t.selectable=!0,t.multiSelectable=!1,n.call(this,e,t)||this}o(e,n);var t=e.prototype;return t.handleClick=function(){var e=this.options_;console.log("Changing quality to:",e.label),n.prototype.handleClick.call(this);for(var t=this.player().qualityLevels(),o=0;o<t.length;o++)e.index==t.length?t[o].enabled=!0:e.index==o?t[o].enabled=!0:t[o].enabled=!1},t.update=function(){var e=this.player().qualityLevels().selectedIndex;this.selected(this.options_.index==e)},e}(e);t.registerComponent("SourceMenuItem",a);var u=r.getComponent("MenuButton"),n=function(i){function e(e,t){var o;o=i.call(this,e,t)||this,u.apply(s(o),arguments);var n=o.player().qualityLevels();if(t&&t.default)if("low"==t.default)for(var l=0;l<n.length;l++)n[l].enabled=0==l;else if(t.default="high")for(l=0;l<n.length;l++)n[l].enabled=l==n.length-1;return o.player().qualityLevels().on(["change","addqualitylevel"],r.bind(s(o),o.update)),o}o(e,i);var t=e.prototype;return t.createEl=function(){return r.dom.createEl("div",{className:"vjs-http-source-selector vjs-menu-button vjs-menu-button-popup vjs-control vjs-button"})},t.buildCSSClass=function(){return u.prototype.buildCSSClass.call(this)+" vjs-icon-cog"},t.update=function(){return u.prototype.update.call(this)},t.createItems=function(){for(var e=[],t=this.player().qualityLevels(),o=[],n=0;n<t.length;n++){var l=t.length-(n+1),i=l===t.selectedIndex,r=""+l,s=l;t[l].height?(r=t[l].height+"p",s=parseInt(t[l].height,10)):t[l].bitrate&&(r=Math.floor(t[l].bitrate/1e3)+" kbps",s=parseInt(t[l].bitrate,10)),0<=o.indexOf(r)||(o.push(r),e.push(new a(this.player_,{label:r,index:l,selected:i,sortVal:s})))}return 1<t.length&&e.push(new a(this.player_,{label:"Auto",index:t.length,selected:!1,sortVal:99999})),e.sort(function(e,t){return e.options_.sortVal<t.options_.sortVal?1:e.options_.sortVal>t.options_.sortVal?-1:0}),e},e}(u),l={},i=r.registerPlugin||r.plugin,c=function(e){var t=this;this.ready(function(){!function(n,e){if(n.addClass("vjs-http-source-selector"),console.log("videojs-http-source-selector initialized!"),console.log("player.techName_:"+n.techName_),"Html5"!=n.techName_)return;n.on(["loadedmetadata"],function(e){if(n.qualityLevels(),r.log("loadmetadata event"),"undefined"==n.videojs_http_source_selector_initialized||1==n.videojs_http_source_selector_initialized)console.log("player.videojs_http_source_selector_initialized == true");else{console.log("player.videojs_http_source_selector_initialized == false"),n.videojs_http_source_selector_initialized=!0;var t=n.controlBar,o=t.getChild("fullscreenToggle").el();t.el().insertBefore(t.addChild("SourceMenuButton").el(),o)}})}(t,r.mergeOptions(l,e))}),r.registerComponent("SourceMenuButton",n),r.registerComponent("SourceMenuItem",a)};return i("httpSourceSelector",c),c.VERSION="1.1.6",c});

4
assets/js/videojs-markers.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
assets/js/videojs-overlay.min.js vendored Normal file
View File

@ -0,0 +1,2 @@
/*! @name videojs-overlay @version 2.1.4 @license Apache-2.0 */
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("video.js"),require("global/window")):"function"==typeof define&&define.amd?define(["video.js","global/window"],e):t.videojsOverlay=e(t.videojs,t.window)}(this,function(t,e){"use strict";function n(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}t=t&&t.hasOwnProperty("default")?t.default:t,e=e&&e.hasOwnProperty("default")?e.default:e;var r={align:"top-left",class:"",content:"This overlay will show up while the video is playing",debug:!1,showBackground:!0,attachToControlBar:!1,overlays:[{start:"playing",end:"paused"}]},i=t.getComponent("Component"),o=t.dom||t,s=t.registerPlugin||t.plugin,a=function(t){return"number"==typeof t&&t==t},h=function(t){return"string"==typeof t&&/^\S+$/.test(t)},d=function(r){var i,s;function d(t,e){var i;return i=r.call(this,t,e)||this,["start","end"].forEach(function(t){var e=i.options_[t];if(a(e))i[t+"Event_"]="timeupdate";else if(h(e))i[t+"Event_"]=e;else if("start"===t)throw new Error('invalid "start" option; expected number or string')}),["endListener_","rewindListener_","startListener_"].forEach(function(t){i[t]=function(e){return d.prototype[t].call(n(n(i)),e)}}),"timeupdate"===i.startEvent_&&i.on(t,"timeupdate",i.rewindListener_),i.debug('created, listening to "'+i.startEvent_+'" for "start" and "'+(i.endEvent_||"nothing")+'" for "end"'),i.hide(),i}s=r,(i=d).prototype=Object.create(s.prototype),i.prototype.constructor=i,i.__proto__=s;var l=d.prototype;return l.createEl=function(){var t=this.options_,n=t.content,r=t.showBackground?"vjs-overlay-background":"vjs-overlay-no-background",i=o.createEl("div",{className:"\n vjs-overlay\n vjs-overlay-"+t.align+"\n "+t.class+"\n "+r+"\n vjs-hidden\n "});return"string"==typeof n?i.innerHTML=n:n instanceof e.DocumentFragment?i.appendChild(n):o.appendContent(i,n),i},l.debug=function(){if(this.options_.debug){for(var e=t.log,n=e,r=arguments.length,i=new Array(r),o=0;o<r;o++)i[o]=arguments[o];e.hasOwnProperty(i[0])&&"function"==typeof e[i[0]]&&(n=e[i.shift()]),n.apply(void 0,["overlay#"+this.id()+": "].concat(i))}},l.hide=function(){return r.prototype.hide.call(this),this.debug("hidden"),this.debug('bound `startListener_` to "'+this.startEvent_+'"'),this.endEvent_&&(this.debug('unbound `endListener_` from "'+this.endEvent_+'"'),this.off(this.player(),this.endEvent_,this.endListener_)),this.on(this.player(),this.startEvent_,this.startListener_),this},l.shouldHide_=function(t,e){var n=this.options_.end;return a(n)?t>=n:n===e},l.show=function(){return r.prototype.show.call(this),this.off(this.player(),this.startEvent_,this.startListener_),this.debug("shown"),this.debug('unbound `startListener_` from "'+this.startEvent_+'"'),this.endEvent_&&(this.debug('bound `endListener_` to "'+this.endEvent_+'"'),this.on(this.player(),this.endEvent_,this.endListener_)),this},l.shouldShow_=function(t,e){var n=this.options_.start,r=this.options_.end;return a(n)?a(r)?t>=n&&t<r:this.hasShownSinceSeek_?Math.floor(t)===n:(this.hasShownSinceSeek_=!0,t>=n):n===e},l.startListener_=function(t){var e=this.player().currentTime();this.shouldShow_(e,t.type)&&this.show()},l.endListener_=function(t){var e=this.player().currentTime();this.shouldHide_(e,t.type)&&this.hide()},l.rewindListener_=function(t){var e=this.player().currentTime(),n=this.previousTime_,r=this.options_.start,i=this.options_.end;e<n&&(this.debug("rewind detected"),a(i)&&!this.shouldShow_(e)?(this.debug("hiding; "+i+" is an integer and overlay should not show at this time"),this.hasShownSinceSeek_=!1,this.hide()):h(i)&&e<r&&(this.debug("hiding; show point ("+r+") is before now ("+e+") and end point ("+i+") is an event"),this.hasShownSinceSeek_=!1,this.hide())),this.previousTime_=e},d}(i);t.registerComponent("Overlay",d);var l=function(e){var n=this,i=t.mergeOptions(r,e);Array.isArray(this.overlays_)&&this.overlays_.forEach(function(t){n.removeChild(t),n.controlBar&&n.controlBar.removeChild(t),t.dispose()});var o=i.overlays;delete i.overlays,this.overlays_=o.map(function(e){var r=t.mergeOptions(i,e),o="string"==typeof r.attachToControlBar||!0===r.attachToControlBar;if(!n.controls()||!n.controlBar)return n.addChild("overlay",r);if(o&&-1!==r.align.indexOf("bottom")){var s=n.controlBar.children()[0];if(void 0!==n.controlBar.getChild(r.attachToControlBar)&&(s=n.controlBar.getChild(r.attachToControlBar)),s){var a=n.controlBar.addChild("overlay",r);return n.controlBar.el().insertBefore(a.el(),s.el()),a}}var h=n.addChild("overlay",r);return n.el().insertBefore(h.el(),n.controlBar.el()),h})};return l.VERSION="2.1.4",s("overlay",l),l});

7
assets/js/videojs-share.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,35 +1,32 @@
'use strict';
var video_data = JSON.parse(document.getElementById('video_data').textContent);
var spinnerHTML = '<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
var spinnerHTMLwithHR = spinnerHTML + '<hr>';
var video_data = JSON.parse(document.getElementById('video_data').innerHTML);
String.prototype.supplant = function (o) {
return this.replace(/{([^{}]*)}/g, function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
});
};
}
function toggle_parent(target) {
var body = target.parentNode.parentNode.children[1];
if (body.style.display === 'none') {
target.textContent = '[ ]';
body.style.display = '';
} else {
target.textContent = '[ + ]';
body = target.parentNode.parentNode.children[1];
if (body.style.display === null || body.style.display === '') {
target.innerHTML = '[ + ]';
body.style.display = 'none';
} else {
target.innerHTML = '[ - ]';
body.style.display = '';
}
}
function toggle_comments(event) {
var target = event.target;
var body = target.parentNode.parentNode.parentNode.children[1];
if (body.style.display === 'none') {
target.textContent = '[ ]';
body.style.display = '';
} else {
target.textContent = '[ + ]';
body = target.parentNode.parentNode.parentNode.children[1];
if (body.style.display === null || body.style.display === '') {
target.innerHTML = '[ + ]';
body.style.display = 'none';
} else {
target.innerHTML = '[ - ]';
body.style.display = '';
}
}
@ -46,13 +43,13 @@ function swap_comments(event) {
function hide_youtube_replies(event) {
var target = event.target;
var sub_text = target.getAttribute('data-inner-text');
var inner_text = target.getAttribute('data-sub-text');
sub_text = target.getAttribute('data-inner-text');
inner_text = target.getAttribute('data-sub-text');
var body = target.parentNode.parentNode.children[1];
body = target.parentNode.parentNode.children[1];
body.style.display = 'none';
target.textContent = sub_text;
target.innerHTML = sub_text;
target.onclick = show_youtube_replies;
target.setAttribute('data-inner-text', inner_text);
target.setAttribute('data-sub-text', sub_text);
@ -61,13 +58,13 @@ function hide_youtube_replies(event) {
function show_youtube_replies(event) {
var target = event.target;
var sub_text = target.getAttribute('data-inner-text');
var inner_text = target.getAttribute('data-sub-text');
sub_text = target.getAttribute('data-inner-text');
inner_text = target.getAttribute('data-sub-text');
var body = target.parentNode.parentNode.children[1];
body = target.parentNode.parentNode.children[1];
body.style.display = '';
target.textContent = sub_text;
target.innerHTML = sub_text;
target.onclick = hide_youtube_replies;
target.setAttribute('data-inner-text', inner_text);
target.setAttribute('data-sub-text', sub_text);
@ -81,259 +78,373 @@ if (continue_button) {
function next_video() {
var url = new URL('https://example.com/watch?v=' + video_data.next_video);
if (video_data.params.autoplay || video_data.params.continue_autoplay)
if (video_data.params.autoplay || video_data.params.continue_autoplay) {
url.searchParams.set('autoplay', '1');
if (video_data.params.listen !== video_data.preferences.listen)
url.searchParams.set('listen', video_data.params.listen);
if (video_data.params.speed !== video_data.preferences.speed)
url.searchParams.set('speed', video_data.params.speed);
if (video_data.params.local !== video_data.preferences.local)
url.searchParams.set('local', video_data.params.local);
url.searchParams.set('continue', '1');
}
if (video_data.params.listen !== video_data.preferences.listen) {
url.searchParams.set('listen', video_data.params.listen);
}
if (video_data.params.speed !== video_data.preferences.speed) {
url.searchParams.set('speed', video_data.params.speed);
}
if (video_data.params.local !== video_data.preferences.local) {
url.searchParams.set('local', video_data.params.local);
}
url.searchParams.set('continue', '1');
location.assign(url.pathname + url.search);
}
function continue_autoplay(event) {
if (event.target.checked) {
player.on('ended', next_video);
player.on('ended', function () {
next_video();
});
} else {
player.off('ended');
}
}
function get_playlist(plid) {
var playlist = document.getElementById('playlist');
function number_with_separator(val) {
while (/(\d+)(\d{3})/.test(val.toString())) {
val = val.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
}
return val;
}
playlist.innerHTML = spinnerHTMLwithHR;
function get_playlist(plid, retries) {
if (retries == undefined) retries = 5;
playlist = document.getElementById('playlist');
if (retries <= 0) {
console.log('Failed to pull playlist');
playlist.innerHTML = '';
return;
}
playlist.innerHTML = ' \
<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3> \
<hr>'
var plid_url;
if (plid.startsWith('RD')) {
plid_url = '/api/v1/mixes/' + plid +
var plid_url = '/api/v1/mixes/' + plid +
'?continuation=' + video_data.id +
'&format=html&hl=' + video_data.preferences.locale;
} else {
plid_url = '/api/v1/playlists/' + plid +
var plid_url = '/api/v1/playlists/' + plid +
'?index=' + video_data.index +
'&continuation=' + video_data.id +
'&format=html&hl=' + video_data.preferences.locale;
}
helpers.xhr('GET', plid_url, {retries: 5, entity_name: 'playlist'}, {
on200: function (response) {
playlist.innerHTML = response.playlistHtml;
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('GET', plid_url, true);
if (!response.nextVideo) return;
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
playlist.innerHTML = xhr.response.playlistHtml;
var nextVideo = document.getElementById(response.nextVideo);
nextVideo.parentNode.parentNode.scrollTop = nextVideo.offsetTop;
if (xhr.response.nextVideo) {
player.on('ended', function () {
var url = new URL('https://example.com/watch?v=' + xhr.response.nextVideo);
player.on('ended', function () {
var url = new URL('https://example.com/watch?v=' + response.nextVideo);
if (video_data.params.autoplay || video_data.params.continue_autoplay) {
url.searchParams.set('autoplay', '1');
}
url.searchParams.set('list', plid);
if (!plid.startsWith('RD'))
url.searchParams.set('index', response.index);
if (video_data.params.autoplay || video_data.params.continue_autoplay)
url.searchParams.set('autoplay', '1');
if (video_data.params.listen !== video_data.preferences.listen)
url.searchParams.set('listen', video_data.params.listen);
if (video_data.params.speed !== video_data.preferences.speed)
url.searchParams.set('speed', video_data.params.speed);
if (video_data.params.local !== video_data.preferences.local)
url.searchParams.set('local', video_data.params.local);
if (video_data.params.listen !== video_data.preferences.listen) {
url.searchParams.set('listen', video_data.params.listen);
}
location.assign(url.pathname + url.search);
});
},
onNon200: function (xhr) {
playlist.innerHTML = '';
document.getElementById('continue').style.display = '';
},
onError: function (xhr) {
playlist.innerHTML = spinnerHTMLwithHR;
},
onTimeout: function (xhr) {
playlist.innerHTML = spinnerHTMLwithHR;
if (video_data.params.speed !== video_data.preferences.speed) {
url.searchParams.set('speed', video_data.params.speed);
}
if (video_data.params.local !== video_data.preferences.local) {
url.searchParams.set('local', video_data.params.local);
}
url.searchParams.set('list', plid);
if (!plid.startsWith('RD')) {
url.searchParams.set('index', xhr.response.index);
}
location.assign(url.pathname + url.search);
});
}
} else {
playlist.innerHTML = '';
document.getElementById('continue').style.display = '';
}
}
});
}
xhr.onerror = function () {
playlist = document.getElementById('playlist');
playlist.innerHTML =
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3><hr>';
console.log('Pulling playlist timed out... ' + retries + '/5');
setTimeout(function () { get_playlist(plid, retries - 1) }, 1000);
}
xhr.ontimeout = function () {
playlist = document.getElementById('playlist');
playlist.innerHTML =
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3><hr>';
console.log('Pulling playlist timed out... ' + retries + '/5');
get_playlist(plid, retries - 1);
}
xhr.send();
}
function get_reddit_comments() {
var comments = document.getElementById('comments');
function get_reddit_comments(retries) {
if (retries == undefined) retries = 5;
comments = document.getElementById('comments');
if (retries <= 0) {
console.log('Failed to pull comments');
comments.innerHTML = '';
return;
}
var fallback = comments.innerHTML;
comments.innerHTML = spinnerHTML;
comments.innerHTML =
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
var url = '/api/v1/comments/' + video_data.id +
'?source=reddit&format=html' +
'&hl=' + video_data.preferences.locale;
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('GET', url, true);
var onNon200 = function (xhr) { comments.innerHTML = fallback; };
if (video_data.params.comments[1] === 'youtube')
onNon200 = function (xhr) {};
helpers.xhr('GET', url, {retries: 5, entity_name: ''}, {
on200: function (response) {
comments.innerHTML = ' \
<div> \
<h3> \
<a href="javascript:void(0)">[ ]</a> \
{title} \
</h3> \
<p> \
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
comments.innerHTML = ' \
<div> \
<h3> \
<a href="javascript:void(0)">[ - ]</a> \
{title} \
</h3> \
<p> \
<b> \
<a href="javascript:void(0)" data-comments="youtube"> \
{youtubeCommentsText} \
</a> \
</b> \
</p> \
<b> \
<a href="javascript:void(0)" data-comments="youtube"> \
{youtubeCommentsText} \
</a> \
<a rel="noopener" target="_blank" href="https://reddit.com{permalink}">{redditPermalinkText}</a> \
</b> \
</p> \
<b> \
<a rel="noopener" target="_blank" href="https://reddit.com{permalink}">{redditPermalinkText}</a> \
</b> \
</div> \
<div>{contentHtml}</div> \
<hr>'.supplant({
title: response.title,
youtubeCommentsText: video_data.youtube_comments_text,
redditPermalinkText: video_data.reddit_permalink_text,
permalink: response.permalink,
contentHtml: response.contentHtml
});
</div> \
<div>{contentHtml}</div> \
<hr>'.supplant({
title: xhr.response.title,
youtubeCommentsText: video_data.youtube_comments_text,
redditPermalinkText: video_data.reddit_permalink_text,
permalink: xhr.response.permalink,
contentHtml: xhr.response.contentHtml
});
comments.children[0].children[0].children[0].onclick = toggle_comments;
comments.children[0].children[1].children[0].onclick = swap_comments;
},
onNon200: onNon200, // declared above
});
comments.children[0].children[0].children[0].onclick = toggle_comments;
comments.children[0].children[1].children[0].onclick = swap_comments;
} else {
if (video_data.params.comments[1] === 'youtube') {
console.log('Pulling comments failed... ' + retries + '/5');
setTimeout(function () { get_youtube_comments(retries - 1) }, 1000);
} else {
comments.innerHTML = fallback;
}
}
}
}
xhr.onerror = function () {
console.log('Pulling comments failed... ' + retries + '/5');
setInterval(function () { get_reddit_comments(retries - 1) }, 1000);
}
xhr.ontimeout = function () {
console.log('Pulling comments failed... ' + retries + '/5');
get_reddit_comments(retries - 1);
}
xhr.send();
}
function get_youtube_comments() {
var comments = document.getElementById('comments');
function get_youtube_comments(retries) {
if (retries == undefined) retries = 5;
comments = document.getElementById('comments');
if (retries <= 0) {
console.log('Failed to pull comments');
comments.innerHTML = '';
return;
}
var fallback = comments.innerHTML;
comments.innerHTML = spinnerHTML;
comments.innerHTML =
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
var url = '/api/v1/comments/' + video_data.id +
'?format=html' +
'&hl=' + video_data.preferences.locale +
'&thin_mode=' + video_data.preferences.thin_mode;
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('GET', url, true);
var onNon200 = function (xhr) { comments.innerHTML = fallback; };
if (video_data.params.comments[1] === 'youtube')
onNon200 = function (xhr) {};
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
comments.innerHTML = ' \
<div> \
<h3> \
<a href="javascript:void(0)">[ - ]</a> \
{commentsText} \
</h3> \
<b> \
<a href="javascript:void(0)" data-comments="reddit"> \
{redditComments} \
</a> \
</b> \
</div> \
<div>{contentHtml}</div> \
<hr>'.supplant({
contentHtml: xhr.response.contentHtml,
redditComments: video_data.reddit_comments_text,
commentsText: video_data.comments_text.supplant(
{ commentCount: number_with_separator(xhr.response.commentCount) }
)
});
helpers.xhr('GET', url, {retries: 5, entity_name: 'comments'}, {
on200: function (response) {
comments.innerHTML = ' \
<div> \
<h3> \
<a href="javascript:void(0)">[ ]</a> \
{commentsText} \
</h3> \
<b> \
<a href="javascript:void(0)" data-comments="reddit"> \
{redditComments} \
</a> \
</b> \
</div> \
<div>{contentHtml}</div> \
<hr>'.supplant({
contentHtml: response.contentHtml,
redditComments: video_data.reddit_comments_text,
commentsText: video_data.comments_text.supplant({
// toLocaleString correctly splits number with local thousands separator. e.g.:
// '1,234,567.89' for user with English locale
// '1 234 567,89' for user with Russian locale
// '1.234.567,89' for user with Portuguese locale
commentCount: response.commentCount.toLocaleString()
})
});
comments.children[0].children[0].children[0].onclick = toggle_comments;
comments.children[0].children[1].children[0].onclick = swap_comments;
},
onNon200: onNon200, // declared above
onError: function (xhr) {
comments.innerHTML = spinnerHTML;
},
onTimeout: function (xhr) {
comments.innerHTML = spinnerHTML;
comments.children[0].children[0].children[0].onclick = toggle_comments;
comments.children[0].children[1].children[0].onclick = swap_comments;
} else {
if (video_data.params.comments[1] === 'youtube') {
setTimeout(function () { get_youtube_comments(retries - 1) }, 1000);
} else {
comments.innerHTML = '';
}
}
}
});
}
xhr.onerror = function () {
comments.innerHTML =
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
console.log('Pulling comments failed... ' + retries + '/5');
setInterval(function () { get_youtube_comments(retries - 1) }, 1000);
}
xhr.ontimeout = function () {
comments.innerHTML =
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
console.log('Pulling comments failed... ' + retries + '/5');
get_youtube_comments(retries - 1);
}
xhr.send();
}
function get_youtube_replies(target, load_more, load_replies) {
function get_youtube_replies(target, load_more) {
var continuation = target.getAttribute('data-continuation');
var body = target.parentNode.parentNode;
var fallback = body.innerHTML;
body.innerHTML = spinnerHTML;
body.innerHTML =
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
var url = '/api/v1/comments/' + video_data.id +
'?format=html' +
'&hl=' + video_data.preferences.locale +
'&thin_mode=' + video_data.preferences.thin_mode +
'&continuation=' + continuation;
if (load_replies) url += '&action=action_get_comment_replies';
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('GET', url, true);
helpers.xhr('GET', url, {}, {
on200: function (response) {
if (load_more) {
body = body.parentNode.parentNode;
body.removeChild(body.lastElementChild);
body.innerHTML += response.contentHtml;
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
if (load_more) {
body = body.parentNode.parentNode;
body.removeChild(body.lastElementChild);
body.innerHTML += xhr.response.contentHtml;
} else {
body.removeChild(body.lastElementChild);
var p = document.createElement('p');
var a = document.createElement('a');
p.appendChild(a);
a.href = 'javascript:void(0)';
a.onclick = hide_youtube_replies;
a.setAttribute('data-sub-text', video_data.hide_replies_text);
a.setAttribute('data-inner-text', video_data.show_replies_text);
a.innerText = video_data.hide_replies_text;
var div = document.createElement('div');
div.innerHTML = xhr.response.contentHtml;
body.appendChild(p);
body.appendChild(div);
}
} else {
body.removeChild(body.lastElementChild);
var p = document.createElement('p');
var a = document.createElement('a');
p.appendChild(a);
a.href = 'javascript:void(0)';
a.onclick = hide_youtube_replies;
a.setAttribute('data-sub-text', video_data.hide_replies_text);
a.setAttribute('data-inner-text', video_data.show_replies_text);
a.textContent = video_data.hide_replies_text;
var div = document.createElement('div');
div.innerHTML = response.contentHtml;
body.appendChild(p);
body.appendChild(div);
body.innerHTML = fallback;
}
},
onNon200: function (xhr) {
body.innerHTML = fallback;
},
onTimeout: function (xhr) {
console.warn('Pulling comments failed');
body.innerHTML = fallback;
}
});
}
xhr.ontimeout = function () {
console.log('Pulling comments failed.');
body.innerHTML = fallback;
}
xhr.send();
}
if (video_data.play_next) {
player.on('ended', function () {
var url = new URL('https://example.com/watch?v=' + video_data.next_video);
if (video_data.params.autoplay || video_data.params.continue_autoplay)
if (video_data.params.autoplay || video_data.params.continue_autoplay) {
url.searchParams.set('autoplay', '1');
if (video_data.params.listen !== video_data.preferences.listen)
url.searchParams.set('listen', video_data.params.listen);
if (video_data.params.speed !== video_data.preferences.speed)
url.searchParams.set('speed', video_data.params.speed);
if (video_data.params.local !== video_data.preferences.local)
url.searchParams.set('local', video_data.params.local);
url.searchParams.set('continue', '1');
}
if (video_data.params.listen !== video_data.preferences.listen) {
url.searchParams.set('listen', video_data.params.listen);
}
if (video_data.params.speed !== video_data.preferences.speed) {
url.searchParams.set('speed', video_data.params.speed);
}
if (video_data.params.local !== video_data.preferences.local) {
url.searchParams.set('local', video_data.params.local);
}
url.searchParams.set('continue', '1');
location.assign(url.pathname + url.search);
});
}
addEventListener('load', function (e) {
if (video_data.plid)
window.addEventListener('load', function (e) {
if (video_data.plid) {
get_playlist(video_data.plid);
}
if (video_data.params.comments[0] === 'youtube') {
get_youtube_comments();
@ -344,7 +455,7 @@ addEventListener('load', function (e) {
} else if (video_data.params.comments[1] === 'reddit') {
get_reddit_comments();
} else {
var comments = document.getElementById('comments');
comments = document.getElementById('comments');
comments.innerHTML = '';
}
});

View File

@ -1,6 +1,4 @@
'use strict';
var watched_data = JSON.parse(document.getElementById('watched_data').textContent);
var payload = 'csrf_token=' + watched_data.csrf_token;
var watched_data = JSON.parse(document.getElementById('watched_data').innerHTML);
function mark_watched(target) {
var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode;
@ -8,27 +6,45 @@ function mark_watched(target) {
var url = '/watch_ajax?action_mark_watched=1&redirect=false' +
'&id=' + target.getAttribute('data-id');
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
helpers.xhr('POST', url, {payload: payload}, {
onNon200: function (xhr) {
tile.style.display = '';
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status != 200) {
tile.style.display = '';
}
}
});
}
xhr.send('csrf_token=' + watched_data.csrf_token);
}
function mark_unwatched(target) {
var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode;
tile.style.display = 'none';
var count = document.getElementById('count');
count.textContent--;
var count = document.getElementById('count')
count.innerText = count.innerText - 1;
var url = '/watch_ajax?action_mark_unwatched=1&redirect=false' +
'&id=' + target.getAttribute('data-id');
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.timeout = 10000;
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
helpers.xhr('POST', url, {payload: payload}, {
onNon200: function (xhr) {
count.textContent++;
tile.style.display = '';
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status != 200) {
count.innerText = count.innerText - 1 + 2;
tile.style.display = '';
}
}
});
}
}
xhr.send('csrf_token=' + watched_data.csrf_token);
}

View File

@ -1,2 +1,3 @@
User-agent: *
Disallow: /
Disallow: /search
Disallow: /login

View File

@ -1,4 +0,0 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View File

@ -1,871 +0,0 @@
#########################################
#
# Database configuration
#
#########################################
##
## Database configuration with separate parameters.
## This setting is MANDATORY, unless 'database_url' is used.
##
db:
user: kemal
password: kemal
host: localhost
port: 5432
dbname: invidious
##
## Database configuration using a single URI. This is an
## alternative to the 'db' parameter above. If both forms
## are used, then only database_url is used.
## This setting is MANDATORY, unless 'db' is used.
##
## Note: The 'database_url' setting allows the use of UNIX
## sockets. To do so, remove the IP address (or FQDN) and port
## and append the 'host' parameter. E.g:
## postgres://kemal:kemal@/invidious?host=/var/run/postgresql
##
## Accepted values: a postgres:// URI
## Default: postgres://kemal:kemal@localhost:5432/invidious
##
#database_url: postgres://kemal:kemal@localhost:5432/invidious
##
## Enable automatic table integrity check. This will create
## the required tables and columns if anything is missing.
##
## Accepted values: true, false
## Default: false
##
#check_tables: false
#########################################
#
# Server config
#
#########################################
# -----------------------------
# Network (inbound)
# -----------------------------
##
## Port to listen on for incoming connections.
##
## Note: Ports lower than 1024 requires either root privileges
## (not recommended) or the "CAP_NET_BIND_SERVICE" capability
## (See https://stackoverflow.com/a/414258 and `man capabilities`)
##
## Accepted values: 1-65535
## Default: 3000
##
#port: 3000
##
## When the invidious instance is behind a proxy, and the proxy
## listens on a different port than the instance does, this lets
## invidious know about it. This is used to craft absolute URLs
## to the instance (e.g in the API).
##
## Note: This setting is MANDATORY if invidious is behind a
## reverse proxy.
##
## Accepted values: 1-65535
## Default: <none>
##
#external_port:
##
## Interface address to listen on for incoming connections.
##
## Accepted values: a valid IPv4 or IPv6 address.
## default: 0.0.0.0 (listen on all interfaces)
##
#host_binding: 0.0.0.0
##
## Domain name under which this instance is hosted. This is
## used to craft absolute URLs to the instance (e.g in the API).
## The domain MUST be defined if your instance is accessed from
## a domain name (like 'example.com').
##
## Accepted values: a fully qualified domain name (FQDN)
## Default: <none>
##
domain:
##
## Tell Invidious that it is behind a proxy that provides only
## HTTPS, so all links must use the https:// scheme. This
## setting MUST be set to true if invidious is behind a
## reverse proxy serving HTTPs.
##
## Accepted values: true, false
## Default: false
##
https_only: false
##
## Enable/Disable 'Strict-Transport-Security'. Make sure that
## the domain specified under 'domain' is served securely.
##
## Accepted values: true, false
## Default: true
##
#hsts: true
# -----------------------------
# Network (outbound)
# -----------------------------
##
## Disable proxying server-wide. Can be disable as a whole, or
## only for a single function.
##
## Accepted values: true, false, dash, livestreams, downloads, local
## Default: false
##
#disable_proxy: false
##
## Size of the HTTP pool used to connect to youtube. Each
## domain ('youtube.com', 'ytimg.com', ...) has its own pool.
##
## Accepted values: a positive integer
## Default: 100
##
#pool_size: 100
##
## Enable/Disable the use of QUIC (HTTP/3) when connecting
## to the youtube API and websites ('youtube.com', 'ytimg.com').
## QUIC's main advantages are its lower latency and lower bandwidth
## use, compared to its predecessors. However, the current version
## of QUIC used in invidious is still based on the IETF draft 31,
## meaning that the underlying library may still not be fully
## optimized. You can read more about QUIC at the link below:
## https://datatracker.ietf.org/doc/html/draft-ietf-quic-transport-31
##
## Note: you should try both options and see what is the best for your
## instance. In general QUIC is recommended for public instances. Your
## mileage may vary.
##
## Note 2: Using QUIC prevents some captcha challenges from appearing.
## See: https://github.com/iv-org/invidious/issues/957#issuecomment-576424042
##
## Accepted values: true, false
## Default: false
##
#use_quic: false
##
## Additional cookies to be sent when requesting the youtube API.
##
## Accepted values: a string in the format "name1=value1; name2=value2..."
## Default: <none>
##
#cookies:
##
## Force connection to youtube over a specific IP family.
##
## Note: This may sometimes resolve issues involving rate-limiting.
## See https://github.com/ytdl-org/youtube-dl/issues/21729.
##
## Accepted values: ipv4, ipv6
## Default: <none>
##
#force_resolve:
# -----------------------------
# Logging
# -----------------------------
##
## Path to log file. Can be absolute or relative to the invidious
## binary. This is overridden if "-o OUTPUT" or "--output=OUTPUT"
## are passed on the command line.
##
## Accepted values: a filesystem path or 'STDOUT'
## Default: STDOUT
##
#output: STDOUT
##
## Logging Verbosity. This is overridden if "-l LEVEL" or
## "--log-level=LEVEL" are passed on the command line.
##
## Accepted values: All, Trace, Debug, Info, Warn, Error, Fatal, Off
## Default: Info
##
#log_level: Info
# -----------------------------
# Features
# -----------------------------
##
## Enable/Disable the "Popular" tab on the main page.
##
## Accepted values: true, false
## Default: true
##
#popular_enabled: true
##
## Enable/Disable statstics (available at /api/v1/stats).
## The following data is available:
## - Software name ("invidious") and version+branch (same data as
## displayed in the footer, e.g: "2021.05.13-75e5b49" / "master")
## - The value of the 'registration_enabled' config (true/false)
## - Number of currently registered users
## - Number of registered users who connected in the last month
## - Number of registered users who connected in the last 6 months
## - Timestamp of the last server restart
## - Timestamp of the last "Channel Refresh" job execution
##
## Warning: This setting MUST be set to true if you plan to run
## a public instance. It is used by api.invidious.io to refresh
## your instance's status.
##
## Accepted values: true, false
## Default: false
##
#statistics_enabled: false
# -----------------------------
# Users and accounts
# -----------------------------
##
## Allow/Forbid Invidious (local) account creation. Invidious
## accounts allow users to subscribe to channels and to create
## playlists without a Google account.
##
## Accepted values: true, false
## Default: true
##
#registration_enabled: true
##
## Allow/Forbid users to log-in. This setting affects the ability
## to connect with BOTH Google and Invidious (local) accounts.
##
## Accepted values: true, false
## Default: true
##
#login_enabled: true
##
## Enable/Disable the captcha challenge on the login page.
##
## Note: this is a basic captcha challenge that doesn't
## depend on any third parties.
##
## Accepted values: true, false
## Default: true
##
#captcha_enabled: true
##
## List of usernames that will be granted administrator rights.
## A user with administrator rights will be able to change the
## server configuration options listed below in /preferences,
## in addition to the usual user preferences.
##
## Server-wide settings:
## - popular_enabled
## - captcha_enabled
## - login_enabled
## - registration_enabled
## - statistics_enabled
## Default user preferences:
## - default_home
## - feed_menu
##
## Accepted values: an array of strings
## Default: [""]
##
#admins: [""]
# -----------------------------
# Background jobs
# -----------------------------
##
## Number of threads to use when crawling channel videos (during
## subscriptions update).
##
## Notes:
## - Setting this to 0 will disable the channel videos crawl job.
## - This setting is overridden if "-c THREADS" or
## "--channel-threads=THREADS" are passed on the command line.
##
## Accepted values: a positive integer
## Default: 1
##
channel_threads: 1
##
## Time interval between two executions of the job that crawls
## channel videos (subscriptions update).
##
## Accepted values: a valid time interval (like 1h30m or 90m)
## Default: 30m
##
#channel_refresh_interval: 30m
##
## Forcefully dump and re-download the entire list of uploaded
## videos when crawling channel (during subscriptions update).
##
## Accepted values: true, false
## Default: false
##
full_refresh: false
##
## Number of threads to use when updating RSS feeds.
##
## Notes:
## - Setting this to 0 will disable the channel videos crawl job.
## - This setting is overridden if "-f THREADS" or
## "--feed-threads=THREADS" are passed on the command line.
##
## Accepted values: a positive integer
## Default: 1
##
feed_threads: 1
##
## Enable/Disable the polling job that keeps the decryption
## function (for "secured" videos) up to date.
##
## Note: This part of the code generate a small amount of data every minute.
## This may not be desired if you have bandwidth limits set by your ISP.
##
## Note 2: This part of the code is currently broken, so changing
## this setting has no impact.
##
## Accepted values: true, false
## Default: false
##
#decrypt_polling: false
# -----------------------------
# Captcha API
# -----------------------------
##
## URL of the captcha solving service.
##
## Accepted values: any URL
## Default: https://api.anti-captcha.com
##
#captcha_api_url: https://api.anti-captcha.com
##
## API key for the captcha solving service.
##
## Accepted values: a string
## Default: <none>
##
#captcha_key:
# -----------------------------
# Miscellaneous
# -----------------------------
##
## custom banner displayed at the top of every page. This can
## used for instance announcements, e.g.
##
## Accepted values: any string. HTML is accepted.
## Default: <none>
##
#banner:
##
## Subscribe to channels using PubSubHub (Google PubSubHubbub service).
## PubSubHub allows Invidious to be instantly notified when a new video
## is published on any subscribed channels. When PubSubHub is not used,
## Invidious will check for new videos every minute.
##
## Note: This setting is recommended for public instances.
##
## Note 2:
## - Requires a public instance (it uses /feed/webhook/v1)
## - Requires 'domain' and 'hmac_key' to be set.
## - Setting this parameter to any number greater than zero will
## enable channel subscriptions via PubSubHub, but will limit the
## amount of concurrent subscriptions.
##
## Accepted values: true, false, a positive integer
## Default: false
##
#use_pubsub_feeds: false
##
## HMAC signing key used for CSRF tokens and pubsub
## subscriptions verification.
##
## Accepted values: a string
## Default: <none>
##
#hmac_key:
##
## List of video IDs where the "download" widget must be
## disabled, in order to comply with DMCA requests.
##
## Accepted values: an array of string
## Default: <none>
##
#dmca_content:
##
## Cache video annotations in the database.
##
## Warning: empty annotations or annotations that only contain
## cards won't be cached.
##
## Accepted values: true, false
## Default: false
##
#cache_annotations: false
##
## Source code URL. If your instance is running a modified source
## code, you MUST publish it somewhere and set this option.
##
## Accepted values: a string
## Default: <none>
##
#modified_source_code_url: ""
#########################################
#
# Default user preferences
#
#########################################
##
## NOTE: All the settings below define the default user
## preferences. They will apply to ALL users connecting
## without a preferences cookie (so either on the first
## connection to the instance or after clearing the
## browser's cookies).
##
default_user_preferences:
# -----------------------------
# Internationalization
# -----------------------------
##
## Default user interface language (locale).
##
## Note: When hosting a public instance, overriding the
## default (english) is not recommended, as it may
## people using other languages.
##
## Accepted values:
## ar (Arabic)
## da (Danish)
## de (German)
## en-US (english, US)
## el (Greek)
## eo (Esperanto)
## es (Spanish)
## fa (Persian)
## fi (Finnish)
## fr (French)
## he (Hebrew)
## hr (Hungarian)
## id (Indonesian)
## is (Icelandic)
## it (Italian)
## ja (Japanese)
## nb-NO (Norwegian, Bokmål)
## nl (Dutch)
## pl (Polish)
## pt-BR (Portuguese, Brazil)
## pt-PT (Portuguese, Portugal)
## ro (Romanian)
## ru (Russian)
## sv (Swedish)
## tr (Turkish)
## uk (Ukrainian)
## zh-CN (Chinese, China) (a.k.a "Simplified Chinese")
## zh-TW (Chinese, Taiwan) (a.k.a "Traditional Chinese")
##
## Default: en-US
##
#locale: en-US
##
## Default geographical location for content.
##
## Accepted values:
## AE, AR, AT, AU, AZ, BA, BD, BE, BG, BH, BO, BR, BY, CA, CH, CL, CO, CR,
## CY, CZ, DE, DK, DO, DZ, EC, EE, EG, ES, FI, FR, GB, GE, GH, GR, GT, HK,
## HN, HR, HU, ID, IE, IL, IN, IQ, IS, IT, JM, JO, JP, KE, KR, KW, KZ, LB,
## LI, LK, LT, LU, LV, LY, MA, ME, MK, MT, MX, MY, NG, NI, NL, NO, NP, NZ,
## OM, PA, PE, PG, PH, PK, PL, PR, PT, PY, QA, RO, RS, RU, SA, SE, SG, SI,
## SK, SN, SV, TH, TN, TR, TW, TZ, UA, UG, US, UY, VE, VN, YE, ZA, ZW
##
## Default: US
##
#region: US
##
## Top 3 preferred languages for video captions.
##
## Note: overriding the default (no preferred
## caption language) is not recommended, in order
## to not penalize people using other languages.
##
## Accepted values: a three-entries array.
## Each entry can be one of:
## "English", "English (auto-generated)",
## "Afrikaans", "Albanian", "Amharic", "Arabic",
## "Armenian", "Azerbaijani", "Bangla", "Basque",
## "Belarusian", "Bosnian", "Bulgarian", "Burmese",
## "Catalan", "Cebuano", "Chinese (Simplified)",
## "Chinese (Traditional)", "Corsican", "Croatian",
## "Czech", "Danish", "Dutch", "Esperanto", "Estonian",
## "Filipino", "Finnish", "French", "Galician", "Georgian",
## "German", "Greek", "Gujarati", "Haitian Creole", "Hausa",
## "Hawaiian", "Hebrew", "Hindi", "Hmong", "Hungarian",
## "Icelandic", "Igbo", "Indonesian", "Irish", "Italian",
## "Japanese", "Javanese", "Kannada", "Kazakh", "Khmer",
## "Korean", "Kurdish", "Kyrgyz", "Lao", "Latin", "Latvian",
## "Lithuanian", "Luxembourgish", "Macedonian",
## "Malagasy", "Malay", "Malayalam", "Maltese", "Maori",
## "Marathi", "Mongolian", "Nepali", "Norwegian Bokmål",
## "Nyanja", "Pashto", "Persian", "Polish", "Portuguese",
## "Punjabi", "Romanian", "Russian", "Samoan",
## "Scottish Gaelic", "Serbian", "Shona", "Sindhi",
## "Sinhala", "Slovak", "Slovenian", "Somali",
## "Southern Sotho", "Spanish", "Spanish (Latin America)",
## "Sundanese", "Swahili", "Swedish", "Tajik", "Tamil",
## "Telugu", "Thai", "Turkish", "Ukrainian", "Urdu",
## "Uzbek", "Vietnamese", "Welsh", "Western Frisian",
## "Xhosa", "Yiddish", "Yoruba", "Zulu"
##
## Default: ["", "", ""]
##
#captions: ["", "", ""]
# -----------------------------
# Interface
# -----------------------------
##
## Enable/Disable dark mode.
##
## Accepted values: true, false
## Default: <none>
##
#dark_mode:
##
## Enable/Disable thin mode (no video thumbnails).
##
## Accepted values: true, false
## Default: false
##
#thin_mode: false
##
## List of feeds available on the home page.
##
## Note: "Subscriptions" and "Playlists" are only visible
## when the user is logged in.
##
## Accepted values: A list of strings
## Each entry can be one of: "Popular", "Trending",
## "Subscriptions", "Playlists"
##
## Default: ["Popular", "Trending", "Subscriptions", "Playlists"] (show all feeds)
##
#feed_menu: ["Popular", "Trending", "Subscriptions", "Playlists"]
##
## Default feed to display on the home page.
##
## Note: setting this option to "Popular" has no
## effect when 'popular_enabled' is set to false.
##
## Accepted values: Popular, Trending, Subscriptions, Playlists, <none>
## Default: Popular
##
#default_home: Popular
##
## Default number of results to display per page.
##
## Note: this affects invidious-generated pages only, such
## as watch history and subscription feeds. Playlists, search
## results and channel videos depend on the data returned by
## the Youtube API.
##
## Accepted values: any positive integer
## Default: 40
##
#max_results: 40
##
## Show/hide annotations.
##
## Accepted values: true, false
## Default: false
##
#annotations: false
##
## Show/hide annotation.
##
## Accepted values: true, false
## Default: false
##
#annotations_subscribed: false
##
## Type of comments to display below video.
##
## Accepted values: a two-entries array.
## Each entry can be one of: "youtube", "reddit", ""
##
## Default: ["youtube", ""]
##
#comments: ["youtube", ""]
##
## Default player style.
##
## Accepted values: invidious, youtube
## Default: invidious
##
#player_style: invidious
##
## Show/Hide the "related videos" sidebar when
## watching a video.
##
## Accepted values: true, false
## Default: true
##
#related_videos: true
# -----------------------------
# Video player behavior
# -----------------------------
##
## Automatically play videos on page load.
##
## Accepted values: true, false
## Default: false
##
#autoplay: false
##
## Automatically load the "next" video (either next in
## playlist or proposed) when the current video ends.
##
## Accepted values: true, false
## Default: false
##
#continue: false
##
## Autoplay next video by default.
##
## Note: Only effective if 'continue' is set to true.
##
## Accepted values: true, false
## Default: true
##
#continue_autoplay: true
##
## Play videos in Audio-only mode by default.
##
## Accepted values: true, false
## Default: false
##
#listen: false
##
## Loop videos automatically.
##
## Accepted values: true, false
## Default: false
##
#video_loop: false
# -----------------------------
# Video playback settings
# -----------------------------
##
## Default video quality.
##
## Accepted values: dash, hd720, medium, small
## Default: hd720
##
#quality: hd720
##
## Default dash video quality.
##
## Note: this setting only takes effet if the
## 'quality' parameter is set to "dash".
##
## Accepted values:
## auto, best, 4320p, 2160p, 1440p, 1080p,
## 720p, 480p, 360p, 240p, 144p, worst
## Default: auto
##
#quality_dash: auto
##
## Default video playback speed.
##
## Accepted values: 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0
## Default: 1.0
##
#speed: 1.0
##
## Default volume.
##
## Accepted values: 0-100
## Default: 100
##
#volume: 100
##
## Allow 360° videos to be played.
##
## Note: This feature requires a WebGL-enabled browser.
##
## Accepted values: true, false
## Default: true
##
#vr_mode: true
# -----------------------------
# Subscription feed
# -----------------------------
##
## In the "Subscription" feed, only show the latest video
## of each channel the user is subscribed to.
##
## Note: when combined with 'unseen_only', the latest unseen
## video of each channel will be displayed instead of the
## latest by date.
##
## Accepted values: true, false
## Default: false
##
#latest_only: false
##
## Enable/Disable user subscriptions desktop notifications.
##
## Accepted values: true, false
## Default: false
##
#notifications_only: false
##
## In the "Subscription" feed, Only show the videos that the
## user haven't watched yet (i.e which are not in their watch
## history).
##
## Accepted values: true, false
## Default: false
##
#unseen_only: false
##
## Default sorting parameter for subscription feeds.
##
## Accepted values:
## 'alphabetically'
## 'alphabetically - reverse'
## 'channel name'
## 'channel name - reverse'
## 'published'
## 'published - reverse'
##
## Default: published
##
#sort: published
# -----------------------------
# Miscellaneous
# -----------------------------
##
## Proxy videos through instance by default.
##
## Warning: As most users won't change this setting in their
## preferences, defaulting to true will significantly
## increase the instance's network usage, so make sure that
## your server's connection can handle it.
##
## Accepted values: true, false
## Default: false
##
#local: false
##
## Show the connected user's nick at the top right.
##
## Accepted values: true, false
## Default: true
##
#show_nick: true
##
## Automatically redirect to a random instance when the user uses
## any "switch invidious instance" link (For videos, it's the plane
## icon, next to "watch on youtube" and "listen"). When set to false,
## the user is sent to https://redirect.invidious.io instead, where
## they can manually select an instance.
##
## Accepted values: true, false
## Default: false
##
#automatic_instance_redirect: false
##
## Show the entire video description by default (when set to 'false',
## only the first few lines of the description are shown and a
## "show more" button allows to expand it).
##
## Accepted values: true, false
## Default: false
##
#extend_desc: false

11
config/config.yml Normal file
View File

@ -0,0 +1,11 @@
channel_threads: 1
feed_threads: 1
db:
user: kemal
password: kemal
host: localhost
port: 5432
dbname: invidious
full_refresh: false
https_only: false
domain:

View File

@ -1,7 +1,4 @@
#!/bin/sh
[ -z "$POSTGRES_USER" ] && POSTGRES_USER=kemal
[ -z "$POSTGRES_DB" ] && POSTGRES_DB=invidious
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE channels ADD COLUMN subscribed bool;"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "UPDATE channels SET subscribed = false;"
psql invidious kemal -c "ALTER TABLE channels ADD COLUMN subscribed bool;"
psql invidious kemal -c "UPDATE channels SET subscribed = false;"

View File

@ -1,10 +1,7 @@
#!/bin/sh
[ -z "$POSTGRES_USER" ] && POSTGRES_USER=kemal
[ -z "$POSTGRES_DB" ] && POSTGRES_DB=invidious
psql invidious kemal -c "ALTER TABLE channel_videos DROP COLUMN live_now CASCADE"
psql invidious kemal -c "ALTER TABLE channel_videos DROP COLUMN premiere_timestamp CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE channel_videos DROP COLUMN live_now CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE channel_videos DROP COLUMN premiere_timestamp CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE channel_videos ADD COLUMN live_now bool"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE channel_videos ADD COLUMN premiere_timestamp timestamptz"
psql invidious kemal -c "ALTER TABLE channel_videos ADD COLUMN live_now bool"
psql invidious kemal -c "ALTER TABLE channel_videos ADD COLUMN premiere_timestamp timestamptz"

View File

@ -1,22 +0,0 @@
#!/bin/sh
[ -z "$POSTGRES_USER" ] && POSTGRES_USER=kemal
[ -z "$POSTGRES_DB" ] && POSTGRES_DB=invidious
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN title CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN views CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN likes CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN dislikes CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN wilson_score CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN published CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN description CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN language CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN author CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN ucid CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN allowed_regions CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN is_family_friendly CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN genre CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN genre_url CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN license CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN sub_count_text CASCADE"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE videos DROP COLUMN author_thumbnail CASCADE"

View File

@ -1,7 +1,4 @@
#!/bin/sh
[ -z "$POSTGRES_USER" ] && POSTGRES_USER=kemal
[ -z "$POSTGRES_DB" ] && POSTGRES_DB=invidious
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE channels ADD COLUMN deleted bool;"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "UPDATE channels SET deleted = false;"
psql invidious kemal -c "ALTER TABLE channels ADD COLUMN deleted bool;"
psql invidious kemal -c "UPDATE channels SET deleted = false;"

View File

@ -1,8 +1,5 @@
#!/bin/sh
[ -z "$POSTGRES_USER" ] && POSTGRES_USER=kemal
[ -z "$POSTGRES_DB" ] && POSTGRES_DB=invidious
psql "$POSTGRES_DB" "$POSTGRES_USER" < config/sql/session_ids.sql
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "INSERT INTO session_ids (SELECT unnest(id), email, CURRENT_TIMESTAMP FROM users) ON CONFLICT (id) DO NOTHING"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE users DROP COLUMN id"
psql invidious kemal < config/sql/session_ids.sql
psql invidious kemal -c "INSERT INTO session_ids (SELECT unnest(id), email, CURRENT_TIMESTAMP FROM users) ON CONFLICT (id) DO NOTHING"
psql invidious kemal -c "ALTER TABLE users DROP COLUMN id"

View File

@ -1,6 +1,3 @@
#!/bin/sh
[ -z "$POSTGRES_USER" ] && POSTGRES_USER=kemal
[ -z "$POSTGRES_DB" ] && POSTGRES_DB=invidious
psql "$POSTGRES_DB" "$POSTGRES_USER" < config/sql/annotations.sql
psql invidious kemal < config/sql/annotations.sql

View File

@ -1,6 +1,3 @@
#!/bin/sh
[ -z "$POSTGRES_USER" ] && POSTGRES_USER=kemal
[ -z "$POSTGRES_DB" ] && POSTGRES_DB=invidious
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE channel_videos ADD COLUMN views bigint;"
psql invidious kemal -c "ALTER TABLE channel_videos ADD COLUMN views bigint;"

View File

@ -1,7 +1,4 @@
#!/bin/sh
[ -z "$POSTGRES_USER" ] && POSTGRES_USER=kemal
[ -z "$POSTGRES_DB" ] && POSTGRES_DB=invidious
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE channel_videos ADD COLUMN live_now bool;"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "UPDATE channel_videos SET live_now = false;"
psql invidious kemal -c "ALTER TABLE channel_videos ADD COLUMN live_now bool;"
psql invidious kemal -c "UPDATE channel_videos SET live_now = false;"

View File

@ -1,6 +1,3 @@
#!/bin/sh
[ -z "$POSTGRES_USER" ] && POSTGRES_USER=kemal
[ -z "$POSTGRES_DB" ] && POSTGRES_DB=invidious
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE users ADD COLUMN feed_needs_update boolean"
psql invidious kemal -c "ALTER TABLE users ADD COLUMN feed_needs_update boolean"

View File

@ -1,6 +1,3 @@
#!/bin/sh
[ -z "$POSTGRES_USER" ] && POSTGRES_USER=kemal
[ -z "$POSTGRES_DB" ] && POSTGRES_DB=invidious
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE channel_videos ADD COLUMN premiere_timestamp timestamptz;"
psql invidious kemal -c "ALTER TABLE channel_videos ADD COLUMN premiere_timestamp timestamptz;"

View File

@ -1,8 +1,5 @@
#!/bin/sh
[ -z "$POSTGRES_USER" ] && POSTGRES_USER=kemal
[ -z "$POSTGRES_DB" ] && POSTGRES_DB=invidious
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE channels DROP COLUMN subscribed"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "ALTER TABLE channels ADD COLUMN subscribed timestamptz"
psql "$POSTGRES_DB" "$POSTGRES_USER" -c "UPDATE channels SET subscribed = '2019-01-01 00:00:00+00'"
psql invidious kemal -c "ALTER TABLE channels DROP COLUMN subscribed"
psql invidious kemal -c "ALTER TABLE channels ADD COLUMN subscribed timestamptz"
psql invidious kemal -c "UPDATE channels SET subscribed = '2019-01-01 00:00:00+00'"

View File

@ -2,11 +2,11 @@
-- DROP TABLE public.annotations;
CREATE TABLE IF NOT EXISTS public.annotations
CREATE TABLE public.annotations
(
id text NOT NULL,
annotations xml,
CONSTRAINT annotations_id_key UNIQUE (id)
);
GRANT ALL ON TABLE public.annotations TO current_user;
GRANT ALL ON TABLE public.annotations TO kemal;

View File

@ -2,7 +2,7 @@
-- DROP TABLE public.channel_videos;
CREATE TABLE IF NOT EXISTS public.channel_videos
CREATE TABLE public.channel_videos
(
id text NOT NULL,
title text,
@ -17,13 +17,13 @@ CREATE TABLE IF NOT EXISTS public.channel_videos
CONSTRAINT channel_videos_id_key UNIQUE (id)
);
GRANT ALL ON TABLE public.channel_videos TO current_user;
GRANT ALL ON TABLE public.channel_videos TO kemal;
-- Index: public.channel_videos_ucid_idx
-- DROP INDEX public.channel_videos_ucid_idx;
CREATE INDEX IF NOT EXISTS channel_videos_ucid_idx
CREATE INDEX channel_videos_ucid_idx
ON public.channel_videos
USING btree
(ucid COLLATE pg_catalog."default");

View File

@ -2,7 +2,7 @@
-- DROP TABLE public.channels;
CREATE TABLE IF NOT EXISTS public.channels
CREATE TABLE public.channels
(
id text NOT NULL,
author text,
@ -12,13 +12,13 @@ CREATE TABLE IF NOT EXISTS public.channels
CONSTRAINT channels_id_key UNIQUE (id)
);
GRANT ALL ON TABLE public.channels TO current_user;
GRANT ALL ON TABLE public.channels TO kemal;
-- Index: public.channels_id_idx
-- DROP INDEX public.channels_id_idx;
CREATE INDEX IF NOT EXISTS channels_id_idx
CREATE INDEX channels_id_idx
ON public.channels
USING btree
(id COLLATE pg_catalog."default");

View File

@ -2,20 +2,20 @@
-- DROP TABLE public.nonces;
CREATE TABLE IF NOT EXISTS public.nonces
CREATE TABLE public.nonces
(
nonce text,
expire timestamp with time zone,
CONSTRAINT nonces_id_key UNIQUE (nonce)
);
GRANT ALL ON TABLE public.nonces TO current_user;
GRANT ALL ON TABLE public.nonces TO kemal;
-- Index: public.nonces_nonce_idx
-- DROP INDEX public.nonces_nonce_idx;
CREATE INDEX IF NOT EXISTS nonces_nonce_idx
CREATE INDEX nonces_nonce_idx
ON public.nonces
USING btree
(nonce COLLATE pg_catalog."default");

View File

@ -2,7 +2,7 @@
-- DROP TABLE public.playlist_videos;
CREATE TABLE IF NOT EXISTS public.playlist_videos
CREATE TABLE playlist_videos
(
title text,
id text,
@ -16,4 +16,4 @@ CREATE TABLE IF NOT EXISTS public.playlist_videos
PRIMARY KEY (index,plid)
);
GRANT ALL ON TABLE public.playlist_videos TO current_user;
GRANT ALL ON TABLE public.playlist_videos TO kemal;

View File

@ -13,7 +13,7 @@ CREATE TYPE public.privacy AS ENUM
-- DROP TABLE public.playlists;
CREATE TABLE IF NOT EXISTS public.playlists
CREATE TABLE public.playlists
(
title text,
id text primary key,
@ -26,4 +26,4 @@ CREATE TABLE IF NOT EXISTS public.playlists
index int8[]
);
GRANT ALL ON public.playlists TO current_user;
GRANT ALL ON public.playlists TO kemal;

View File

@ -2,7 +2,7 @@
-- DROP TABLE public.session_ids;
CREATE TABLE IF NOT EXISTS public.session_ids
CREATE TABLE public.session_ids
(
id text NOT NULL,
email text,
@ -10,13 +10,13 @@ CREATE TABLE IF NOT EXISTS public.session_ids
CONSTRAINT session_ids_pkey PRIMARY KEY (id)
);
GRANT ALL ON TABLE public.session_ids TO current_user;
GRANT ALL ON TABLE public.session_ids TO kemal;
-- Index: public.session_ids_id_idx
-- DROP INDEX public.session_ids_id_idx;
CREATE INDEX IF NOT EXISTS session_ids_id_idx
CREATE INDEX session_ids_id_idx
ON public.session_ids
USING btree
(id COLLATE pg_catalog."default");

View File

@ -2,7 +2,7 @@
-- DROP TABLE public.users;
CREATE TABLE IF NOT EXISTS public.users
CREATE TABLE public.users
(
updated timestamp with time zone,
notifications text[],
@ -16,13 +16,13 @@ CREATE TABLE IF NOT EXISTS public.users
CONSTRAINT users_email_key UNIQUE (email)
);
GRANT ALL ON TABLE public.users TO current_user;
GRANT ALL ON TABLE public.users TO kemal;
-- Index: public.email_unique_idx
-- DROP INDEX public.email_unique_idx;
CREATE UNIQUE INDEX IF NOT EXISTS email_unique_idx
CREATE UNIQUE INDEX email_unique_idx
ON public.users
USING btree
(lower(email) COLLATE pg_catalog."default");

View File

@ -2,21 +2,38 @@
-- DROP TABLE public.videos;
CREATE UNLOGGED TABLE IF NOT EXISTS public.videos
CREATE TABLE public.videos
(
id text NOT NULL,
info text,
updated timestamp with time zone,
title text,
views bigint,
likes integer,
dislikes integer,
wilson_score double precision,
published timestamp with time zone,
description text,
language text,
author text,
ucid text,
allowed_regions text[],
is_family_friendly boolean,
genre text,
genre_url text,
license text,
sub_count_text text,
author_thumbnail text,
CONSTRAINT videos_pkey PRIMARY KEY (id)
);
GRANT ALL ON TABLE public.videos TO current_user;
GRANT ALL ON TABLE public.videos TO kemal;
-- Index: public.id_idx
-- DROP INDEX public.id_idx;
CREATE UNIQUE INDEX IF NOT EXISTS id_idx
CREATE UNIQUE INDEX id_idx
ON public.videos
USING btree
(id COLLATE pg_catalog."default");

View File

@ -1,12 +1,14 @@
# 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"
version: '3'
services:
postgres:
build:
context: .
dockerfile: docker/Dockerfile.postgres
restart: unless-stopped
volumes:
- postgresdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
invidious:
build:
context: .
@ -15,42 +17,21 @@ services:
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
# Adapted from ./config/config.yml
INVIDIOUS_CONFIG: |
channel_threads: 1
feed_threads: 1
db:
dbname: invidious
user: kemal
password: kemal
host: invidious-db
host: postgres
port: 5432
check_tables: true
# external_port:
# domain:
# https_only: false
# statistics_enabled: false
healthcheck:
test: wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/comments/jNQXAC9IVRw || exit 1
interval: 30s
timeout: 5s
retries: 2
dbname: invidious
full_refresh: false
https_only: false
domain:
depends_on:
- invidious-db
invidious-db:
image: docker.io/library/postgres:13
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"]
- postgres
volumes:
postgresdata:

View File

@ -1,54 +1,38 @@
FROM crystallang/crystal:1.4.1-alpine AS builder
RUN apk add --no-cache sqlite-static yaml-static
ARG release
FROM alpine:edge AS builder
RUN apk add --no-cache curl crystal shards libc-dev \
yaml-dev libxml2-dev sqlite-dev zlib-dev openssl-dev \
yaml-static sqlite-static zlib-static openssl-libs-static
WORKDIR /invidious
RUN curl -Lo /etc/apk/keys/omarroth.rsa.pub https://github.com/omarroth/boringssl-alpine/releases/download/1.1.0-r0/omarroth.rsa.pub && \
curl -Lo boringssl-dev.apk https://github.com/omarroth/boringssl-alpine/releases/download/1.1.0-r0/boringssl-dev-1.1.0-r0.apk && \
curl -Lo lsquic.apk https://github.com/omarroth/lsquic-alpine/releases/download/2.6.3-r0/lsquic-2.6.3-r0.apk && \
apk verify --no-cache boringssl-dev.apk lsquic.apk && \
tar -xf boringssl-dev.apk usr/lib/libcrypto.a usr/lib/libssl.a && \
tar -xf lsquic.apk usr/lib/liblsquic.a && \
rm /etc/apk/keys/omarroth.rsa.pub boringssl-dev.apk lsquic.apk
COPY ./shard.yml ./shard.yml
COPY ./shard.lock ./shard.lock
RUN shards install --production
COPY --from=quay.io/invidious/lsquic-compiled /root/liblsquic.a ./lib/lsquic/src/lsquic/ext/liblsquic.a
RUN shards update && shards install && \
mv ./usr/lib/* ./lib/lsquic/src/lsquic/ext && \
rm -r ./usr /root/.cache
COPY ./src/ ./src/
# TODO: .git folder is required for building this is destructive.
# See definition of CURRENT_BRANCH, CURRENT_COMMIT and CURRENT_VERSION.
COPY ./.git/ ./.git/
# Required for fetching player dependencies
COPY ./scripts/ ./scripts/
COPY ./assets/ ./assets/
COPY ./videojs-dependencies.yml ./videojs-dependencies.yml
RUN crystal spec --warnings all \
RUN crystal build ./src/invidious.cr \
--static --warnings all --error-on-warnings \
--link-flags "-lxml2 -llzma"
RUN if [ "${release}" == 1 ] ; then \
crystal build ./src/invidious.cr \
--release \
--static --warnings all \
--link-flags "-lxml2 -llzma"; \
else \
crystal build ./src/invidious.cr \
--static --warnings all \
--link-flags "-lxml2 -llzma"; \
fi
FROM alpine:latest
RUN apk add --no-cache librsvg ttf-opensans
WORKDIR /invidious
RUN addgroup -g 1000 -S invidious && \
adduser -u 1000 -S invidious -G invidious
COPY --chown=invidious ./config/config.* ./config/
RUN mv -n config/config.example.yml config/config.yml
RUN sed -i 's/host: \(127.0.0.1\|localhost\)/host: invidious-db/' config/config.yml
COPY ./assets/ ./assets/
COPY --chown=invidious ./config/config.yml ./config/config.yml
RUN sed -i 's/host: \(127.0.0.1\|localhost\)/host: postgres/' config/config.yml
COPY ./config/sql/ ./config/sql/
COPY ./locales/ ./locales/
COPY --from=builder /invidious/assets ./assets/
COPY --from=builder /invidious/invidious .
RUN chmod o+rX -R ./assets ./config ./locales
EXPOSE 3000
USER invidious
CMD [ "/invidious/invidious" ]

View File

@ -1,53 +0,0 @@
FROM alpine:3.16 AS builder
RUN apk add --no-cache 'crystal=1.4.1-r0' shards sqlite-static yaml-static yaml-dev libxml2-dev zlib-static openssl-libs-static openssl-dev musl-dev
ARG release
WORKDIR /invidious
COPY ./shard.yml ./shard.yml
COPY ./shard.lock ./shard.lock
RUN shards install --production
COPY --from=quay.io/invidious/lsquic-compiled /root/liblsquic.a ./lib/lsquic/src/lsquic/ext/liblsquic.a
COPY ./src/ ./src/
# TODO: .git folder is required for building this is destructive.
# See definition of CURRENT_BRANCH, CURRENT_COMMIT and CURRENT_VERSION.
COPY ./.git/ ./.git/
# Required for fetching player dependencies
COPY ./scripts/ ./scripts/
COPY ./assets/ ./assets/
COPY ./videojs-dependencies.yml ./videojs-dependencies.yml
RUN crystal spec --warnings all \
--link-flags "-lxml2 -llzma"
RUN if [ ${release} == 1 ] ; then \
crystal build ./src/invidious.cr \
--release \
--static --warnings all \
--link-flags "-lxml2 -llzma"; \
else \
crystal build ./src/invidious.cr \
--static --warnings all \
--link-flags "-lxml2 -llzma"; \
fi
FROM alpine:3.16
RUN apk add --no-cache librsvg ttf-opensans
WORKDIR /invidious
RUN addgroup -g 1000 -S invidious && \
adduser -u 1000 -S invidious -G invidious
COPY --chown=invidious ./config/config.* ./config/
RUN mv -n config/config.example.yml config/config.yml
RUN sed -i 's/host: \(127.0.0.1\|localhost\)/host: invidious-db/' config/config.yml
COPY ./config/sql/ ./config/sql/
COPY ./locales/ ./locales/
COPY --from=builder /invidious/assets ./assets/
COPY --from=builder /invidious/invidious .
RUN chmod o+rX -R ./assets ./config ./locales
EXPOSE 3000
USER invidious
CMD [ "/invidious/invidious" ]

View File

@ -0,0 +1,12 @@
FROM postgres:10
ENV POSTGRES_USER postgres
# Do not require a PostgreSQL superuser password.
# See https://github.com/docker-library/postgres/issues/681.
ENV POSTGRES_HOST_AUTH_METHOD trust
ADD ./config/sql /config/sql
ADD ./docker/entrypoint.postgres.sh /entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh" ]
CMD [ "postgres" ]

30
docker/entrypoint.postgres.sh Executable file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env bash
CMD="$@"
if [ ! -f /var/lib/postgresql/data/setupFinished ]; then
echo "### first run - setting up invidious database"
/usr/local/bin/docker-entrypoint.sh postgres &
sleep 10
until runuser -l postgres -c 'pg_isready' 2>/dev/null; do
>&2 echo "### Postgres is unavailable - waiting"
sleep 5
done
>&2 echo "### importing table schemas"
su postgres -c 'createdb invidious'
su postgres -c 'psql -c "CREATE USER kemal WITH PASSWORD '"'kemal'"'"'
su postgres -c 'psql invidious kemal < config/sql/channels.sql'
su postgres -c 'psql invidious kemal < config/sql/videos.sql'
su postgres -c 'psql invidious kemal < config/sql/channel_videos.sql'
su postgres -c 'psql invidious kemal < config/sql/users.sql'
su postgres -c 'psql invidious kemal < config/sql/session_ids.sql'
su postgres -c 'psql invidious kemal < config/sql/nonces.sql'
su postgres -c 'psql invidious kemal < config/sql/annotations.sql'
su postgres -c 'psql invidious kemal < config/sql/playlists.sql'
su postgres -c 'psql invidious kemal < config/sql/playlist_videos.sql'
touch /var/lib/postgresql/data/setupFinished
echo "### invidious database setup finished"
exit
fi
echo "running postgres /usr/local/bin/docker-entrypoint.sh $CMD"
exec /usr/local/bin/docker-entrypoint.sh $CMD

View File

@ -1,12 +0,0 @@
#!/bin/bash
set -eou pipefail
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/channels.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/videos.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/channel_videos.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/users.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/session_ids.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/nonces.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/annotations.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/playlists.sql
psql --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" < config/sql/playlist_videos.sql

View File

@ -1,6 +1,6 @@
dependencies:
- name: postgresql
repository: https://charts.bitnami.com/bitnami/
version: 11.1.3
digest: sha256:79061645472b6fb342d45e8e5b3aacd018ef5067193e46a060bccdc99fe7f6e1
generated: "2022-03-02T05:57:20.081432389+13:00"
repository: https://kubernetes-charts.storage.googleapis.com/
version: 8.3.0
digest: sha256:1feec3c396cbf27573dc201831ccd3376a4a6b58b2e7618ce30a89b8f5d707fd
generated: "2020-02-07T13:39:38.624846+01:00"

View File

@ -1,7 +1,7 @@
apiVersion: v2
name: invidious
description: Invidious is an alternative front-end to YouTube
version: 1.1.1
version: 1.0.0
appVersion: 0.20.1
keywords:
- youtube
@ -9,14 +9,14 @@ keywords:
- video
- privacy
home: https://invidio.us/
icon: https://raw.githubusercontent.com/iv-org/invidious/05988c1c49851b7d0094fca16aeaf6382a7f64ab/assets/favicon-32x32.png
icon: https://raw.githubusercontent.com/omarroth/invidious/05988c1c49851b7d0094fca16aeaf6382a7f64ab/assets/favicon-32x32.png
sources:
- https://github.com/iv-org/invidious
- https://github.com/omarroth/invidious
maintainers:
- name: Leon Klingele
email: mail@leonklingele.de
dependencies:
- name: postgresql
version: ~11.1.3
repository: "https://charts.bitnami.com/bitnami/"
version: ~8.3.0
repository: "https://kubernetes-charts.storage.googleapis.com/"
engine: gotpl

View File

@ -23,13 +23,6 @@ spec:
runAsUser: {{ .Values.securityContext.runAsUser }}
runAsGroup: {{ .Values.securityContext.runAsGroup }}
fsGroup: {{ .Values.securityContext.fsGroup }}
initContainers:
- name: wait-for-postgresql
image: postgres
args:
- /bin/sh
- -c
- until pg_isready -h {{ .Values.config.db.host }} -p {{ .Values.config.db.port }} -U {{ .Values.config.db.user }}; do echo waiting for database; sleep 2; done;
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
@ -57,5 +50,4 @@ spec:
httpGet:
port: 3000
path: /
initialDelaySeconds: 15
restartPolicy: Always

View File

@ -7,14 +7,10 @@ metadata:
chart: {{ .Chart.Name }}
release: {{ .Release.Name }}
spec:
type: {{ .Values.service.type }}
ports:
- name: http
port: {{ .Values.service.port }}
port: 3000
targetPort: 3000
selector:
app: {{ template "invidious.name" . }}
release: {{ .Release.Name }}
{{- if .Values.service.loadBalancerIP }}
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
{{- end }}

View File

@ -1,7 +1,7 @@
name: invidious
image:
repository: quay.io/invidious/invidious
repository: omarroth/invidious
tag: latest
pullPolicy: Always
@ -13,11 +13,6 @@ autoscaling:
maxReplicas: 16
targetCPUUtilizationPercentage: 50
service:
type: ClusterIP
port: 3000
#loadBalancerIP:
resources: {}
#requests:
# cpu: 100m
@ -32,19 +27,14 @@ securityContext:
runAsGroup: 1000
fsGroup: 1000
# See https://github.com/bitnami/charts/tree/master/bitnami/postgresql
# See https://github.com/helm/charts/tree/master/stable/postgresql
postgresql:
image:
registry: quay.io
auth:
username: kemal
password: kemal
database: invidious
primary:
initdb:
username: kemal
password: kemal
scriptsConfigMap: invidious-postgresql-init
postgresqlUsername: kemal
postgresqlPassword: kemal
postgresqlDatabase: invidious
initdbUsername: kemal
initdbPassword: kemal
initdbScriptsConfigMap: invidious-postgresql-init
# Adapted from ../config/config.yml
config:

View File

@ -1,127 +1,128 @@
{
"LIVE": "مُباشِر",
"Shared `x` ago": "تمَّ رفع المقطع المرئيّ مُنذ `x`",
"Unsubscribe": "إلغاء الاشتراك",
"Subscribe": "الإشتراك",
"`x` subscribers": "`x` المشتركين",
"`x` videos": "`x` الفيديوهات",
"`x` playlists": "`x` قوائم التشغيل",
"LIVE": "مباشر",
"Shared `x` ago": "تم رفع الفيديو منذ `x`",
"Unsubscribe": "إلغاء الإشتراك",
"Subscribe": "إشتراك",
"View channel on YouTube": "زيارة القناة على موقع يوتيوب",
"View playlist on YouTube": "عرض قائمة التشغيل على اليوتيوب",
"newest": "الأجدد",
"oldest": "الأقدم",
"popular": "الأكثر شعبية",
"last": "الأخيرة",
"Next page": "الصفحة التالية",
"last": "اخر قوائم التشغيل المعدلة",
"Next page": "الصفحة الثانية",
"Previous page": "الصفحة السابقة",
"Clear watch history?": "هل تريد محو سجل المشاهدة؟",
"New password": "كلمة مرور جديدة",
"New passwords must match": "يَجبُ أن تكون كلمتا المرور متطابقتين",
"Cannot change password for Google accounts": "لا يُمكن تغيير كلمة المرور لِحسابات جوجل",
"Authorize token?": "رمز التفويض؟",
"Authorize token for `x`?": "السماح بالرمز المميز ل 'x'؟",
"Clear watch history?": "مسح السجل ؟",
"New password": "الرقم السرى الجديد",
"New passwords must match": "الأرقام السرية يجب ان تكون متطابقة",
"Cannot change password for Google accounts": "لا يستطيع تغيير الرقم السرى لحساب جوجل",
"Authorize token?": "رمز الإذن ؟",
"Authorize token for `x`?": "تصريح الرمز لـ `x` ؟",
"Yes": "نعم",
"No": "لا",
"Import and Export Data": "اِستيراد البيانات وتصديرها",
"Import": "استيراد",
"Import Invidious data": "استيراد بيانات JSON Invidious",
"Import YouTube subscriptions": "استيراد اشتراكات YouTube/OPML",
"Import FreeTube subscriptions (.db)": "استيراد اشتراكات فريتيوب (.db)",
"Import NewPipe subscriptions (.json)": "استيراد اشتراكات نيو بايب (.json)",
"Import NewPipe data (.zip)": "استيراد بيانات نيو بايب (.zip)",
"Export": "تصدير",
"Export subscriptions as OPML": "تصدير الاشتراكات كـOPML",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "تصدير الاشتراكات كـOPML (لِنيو بايب و فريتيوب)",
"Export data as JSON": "تصدير بيانات Invidious كـ JSON",
"Delete account?": "حذف الحساب؟",
"History": "السِّجل",
"An alternative front-end to YouTube": "واجهة أمامية بديلة لموقع يوتيوب",
"JavaScript license information": "معلومات ترخيص جافا سكربت",
"Import and Export Data": "استخراج و إضافة البيانات",
"Import": "إضافة",
"Import Invidious data": "إضافة بيانات Invidious",
"Import YouTube subscriptions": "إضافةالإشتراكات من موقع يوتيوب",
"Import FreeTube subscriptions (.db)": "إضافةالمشتركين من FreeTube (.db)",
"Import NewPipe subscriptions (.json)": "إضافة المشتركين من NewPipe (.json)",
"Import NewPipe data (.zip)": "إضافة بيانات NewPipe (.zip)",
"Export": "استخراج",
"Export subscriptions as OPML": "استخراج المشتركين كـ OPML",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "استخراج المشتركين كـ OPML (لـ NewPipe و FreeTube)",
"Export data as JSON": "استخراج البيانات كـ JSON",
"Delete account?": "حذف الحساب ؟",
"History": "السجل",
"An alternative front-end to YouTube": "البديل الكامل لموقع يوتيوب",
"JavaScript license information": "معلومات ترخيص JavaScript",
"source": "المصدر",
"Log in": "تسجيل الدخول",
"Log in/register": "تسجيل الدخول \\ إنشاء حساب",
"Log in with Google": "تسجيل الدخول باستخدام جوجل",
"User ID": ُعرِّف المُستخدم",
"Password": "كلمة المرور",
"Time (h:mm:ss):": "الوقت (h:mm:ss):",
"Text CAPTCHA": "نص الكابتشا",
"Image CAPTCHA": "صورة الكابتشا",
"Log in/register": "تسجيل الدخول\\إنشاء حساب",
"Log in with Google": "تسجيل الدخول بإستخدام جوجل",
"User ID": "إسم المستخدم",
"Password": "الرقم السرى",
"Time (h:mm:ss):": "(يجب ان يكتب مثل هذا التنسيق) الوقت (h(ساعات):mm(دقائق):ss(ثوانى)):",
"Text CAPTCHA": "CAPTCHA كلامية",
"Image CAPTCHA": "CAPTCHA صورية",
"Sign In": "تسجيل الدخول",
"Register": "التسجيل",
"E-mail": "البريد الإلكتروني",
"Register": "انشاء الحساب",
"E-mail": "الإيميل",
"Google verification code": "رمز تحقق جوجل",
"Preferences": "الإعدادات",
"preferences_category_player": "إعدادات المُشغِّل",
"preferences_video_loop_label": "كرر المقطع المرئيّ دائما: ",
"preferences_autoplay_label": "تشغيل تلقائي: ",
"preferences_continue_label": "شغل المقطع التالي تلقائيًا: ",
"preferences_continue_autoplay_label": "شغل المقطع التالي تلقائيًا: ",
"preferences_listen_label": "تشغيل النسخة السمعية تلقائيًا: ",
"preferences_local_label": "بروكسي المقاطع المرئيّة؟ ",
"preferences_speed_label": "السرعة الافتراضية: ",
"preferences_quality_label": "الجودة المفضلة للمقاطع: ",
"preferences_volume_label": "صوت المشغل: ",
"preferences_comments_label": "التعليقات الافتراضية: ",
"Preferences": "التفضيلات",
"Player preferences": "التفضيلات المشغل",
"Always loop: ": "كرر الفيديو دائما: ",
"Autoplay: ": "تشغيل تلقائى: ",
"Play next by default: ": "شغل الفيديو التالي تلقائيا: ",
"Autoplay next video: ": "شغل الفيديو التالي تلقائيا (في قوائم التشغيل) ",
"Listen by default: ": "تشغيل النسخة السمعية تلقائى: ",
"Proxy videos: ": "عرض الفيديوهات عن طريق البروكسي؟ ",
"Default speed: ": "السرعة الإفتراضية: ",
"Preferred video quality: ": "الجودة المفضلة للفيديوهات: ",
"Player volume: ": "صوت المشغل: ",
"Default comments: ": "إضهار التعليقات الإفتراضية لـ: ",
"youtube": "يوتيوب",
"reddit": "ريديت",
"preferences_captions_label": "التسميات التوضيحية الإفتراضية: ",
"Fallback captions: ": "التسميات التوضيحية الاحتياطيَّة: ",
"preferences_related_videos_label": "اعرض الفيديوهات ذات الصلة: ",
"preferences_annotations_label": "اعرض الملاحظات في الفيديو تلقائيا: ",
"preferences_extend_desc_label": "توسيع وصف الفيديو تلقائيا: ",
"preferences_vr_mode_label": "مقاطع فيديو تفاعلية بزاوية 360 درجة (تتطلب WebGL): ",
"preferences_category_visual": "التفضيلات المرئية",
"preferences_player_style_label": "شكل مشغل الفيديوهات: ",
"Dark mode: ": "الوضع الليلي: ",
"preferences_dark_mode_label": "المظهر: ",
"reddit": "Reddit",
"Default captions: ": "الترجمات الإفتراضية: ",
"Fallback captions: ": "الترجمات المصاحبة: ",
"Show related videos: ": "اعرض الفيديوهات ذات الصلة: ",
"Show annotations by default: ": "اعرض الملاحظات في الفيديو تلقائيا: ",
"Visual preferences": "التفضيلات المرئية",
"Player style: ": "شكل مشغل الفيديوهات: ",
"Dark mode: ": "الوضع الليلى: ",
"Theme: ": "المظهر: ",
"dark": "غامق (اسود)",
"light": "فاتح (ابيض)",
"preferences_thin_mode_label": "الوضع الخفيف: ",
"preferences_category_misc": "تفضيلات متنوعة",
"preferences_automatic_instance_redirect_label": "إعادة توجيه المثيل التلقائي (إعادة التوجيه إلى redirect.invidious.io): ",
"preferences_category_subscription": "تفضيلات الاشتراك",
"preferences_annotations_subscribed_label": "عرض الملاحظات في الفيديوهات تلقائيا في القنوات المشترك بها فقط: ",
"Thin mode: ": "الوضع الخفيف: ",
"Subscription preferences": "تفضيلات الإشتراك",
"Show annotations by default for subscribed channels: ": "عرض الملاحظات في الفيديوهات تلقائيا في القنوات المشترك بها فقط: ",
"Redirect homepage to feed: ": "إعادة التوجية من الصفحة الرئيسية لصفحة المشتركين (لرؤية اخر فيديوهات المشتركين): ",
"preferences_max_results_label": "عدد الفيديوهات التى ستظهر فى صفحة المشتركين: ",
"preferences_sort_label": "ترتيب الفيديوهات بـ: ",
"published": "أحدث فيديو",
"published - reverse": "أحدث فيديو - عكسي",
"alphabetically": "ترتيب أبجدي",
"alphabetically - reverse": "أبجدي - عكسي",
"channel name": اسم القناة",
"channel name - reverse": اسم القناة - عكسى",
"Only show latest video from channel: ": "فقط أظهر آخر فيديو من القناة: ",
"Only show latest unwatched video from channel: ": "فقط أظهر آخر فيديو لم يتم رؤيته من القناة: ",
"preferences_unseen_only_label": "فقط أظهر الذي لم يتم رؤيته: ",
"preferences_notifications_only_label": "إظهار الإشعارات فقط (إذا كان هناك أي): ",
"Number of videos shown in feed: ": "عدد الفيديوهات التى ستظهر فى صفحة المشتركين: ",
"Sort videos by: ": "ترتيب الفيديو بـ: ",
"published": "احدث فيديو",
"published - reverse": "احدث فيديو - عكسى",
"alphabetically": "ترتيب ابجدى",
"alphabetically - reverse": "ابجدى - عكسى",
"channel name": إسم القناة",
"channel name - reverse": إسم القناة - عكسى",
"Only show latest video from channel: ": "فقط إظهر اخر فيديو من القناة: ",
"Only show latest unwatched video from channel: ": "فقط اظهر اخر فيديو لم يتم رؤيتة من القناة: ",
"Only show unwatched: ": "فقط اظهر الذى لم يتم رؤيتة: ",
"Only show notifications (if there are any): ": "إظهار الإشعارات فقط (إذا كان هناك أي): ",
"Enable web notifications": "تفعيل إشعارات المتصفح",
"`x` uploaded a video": "`x` رفع فيديو",
"`x` is live": "`x` في بث مباشر",
"preferences_category_data": "إعدادات التفضيلات",
"`x` is live": "`x` فى بث مباشر",
"Data preferences": "إعدادات التفضيلات",
"Clear watch history": "حذف سجل المشاهدة",
"Import/export data": "إضافة\\استخراج البيانات",
"Change password": "غير كلمة السر",
"Manage subscriptions": "إدارة الاشتراكات",
"Import/export data": "إضافة\\إستخراج البيانات",
"Change password": "غير الرقم السرى",
"Manage subscriptions": "إدارة المشتركين",
"Manage tokens": "إدارة الرموز",
"Watch history": "سجل المشاهدة",
"Delete account": "حذف الحساب",
"preferences_category_admin": "إعدادات المدير",
"preferences_default_home_label": "الصفحة الرئيسية الافتراضية: ",
"preferences_feed_menu_label": "قائمة التدفقات: ",
"preferences_show_nick_label": "إظهار اللقب في الأعلى: ",
"Administrator preferences": "إعدادات المدير",
"Default homepage: ": "الصفحة الرئيسية الافتراضية ",
"Feed menu: ": "قائمة التدفقات: ",
"Top enabled: ": "تفعيل 'الأفضل' ؟ ",
"CAPTCHA enabled: ": "تفعيل الكابتشا: ",
"Login enabled: ": مكين تسجيل الدخول: ",
"Login enabled: ": فعيل الولوج: ",
"Registration enabled: ": "تفعيل التسجيل: ",
"Report statistics: ": "تقرير الإحصائيات: ",
"Save preferences": "حفظ الإعدادات",
"Subscription manager": "مدير الاشتراكات",
"Report statistics: ": "الإبلاغ عن الإحصائيات: ",
"Save preferences": "حفظ التفضيلات",
"Subscription manager": "مدير الإشتراكات",
"Token manager": "إداره الرمز",
"Token": "الرمز",
"Import/export": "استيراد/تصدير",
"unsubscribe": "إلغاء الاشتراك",
"`x` subscriptions": "`x` مشتركين",
"`x` tokens": "`x` رموز",
"Import/export": "إضافة\\إستخراج",
"unsubscribe": "إلغاء الإشتراك",
"revoke": "مسح",
"Subscriptions": "الاشتراكات",
"Subscriptions": "الإشتراكات",
"`x` unseen notifications": "`x` إشعارات لم تشاهدها بعد",
"search": "بحث",
"Log out": "تسجيل الخروج",
"Released under the AGPLv3 on Github.": "صدر تحت AGPLv3 على GitHub.",
"Released under the AGPLv3 by Omar Roth.": "تم الإنشاء تحت AGPLv3 بواسطة عمر روث.",
"Source available here.": "الأكواد متوفرة هنا.",
"View JavaScript license information.": "مشاهدة معلومات حول تراخيص الجافاسكريبت.",
"View privacy policy.": "عرض سياسة الخصوصية.",
@ -131,82 +132,79 @@
"Private": "خاص",
"View all playlists": "عرض جميع قوائم التشغيل",
"Updated `x` ago": "تم تحديثه منذ `x`",
"Delete playlist `x`?": "حذف قائمة التشغيل `x`؟",
"Delete playlist": "حذف قائمة التغشيل",
"Create playlist": "إنشاء قائمة تشغيل",
"Delete playlist `x`?": "حذف قائمه التشغيل `x` ?",
"Delete playlist": "حذف قائمه التغشيل",
"Create playlist": "إنشاء قائمه تشغيل",
"Title": "العنوان",
"Playlist privacy": "إعدادات الخصوصية",
"Editing playlist `x`": "تعديل قائمة التشغيل `x`",
"Show more": "إظهار المزيد",
"Show less": "عرض اقل",
"Playlist privacy": "إعدادات الخصوصيه",
"Editing playlist `x`": "تعديل قائمه التشفيل `x`",
"Watch on YouTube": "مشاهدة الفيديو على اليوتيوب",
"Switch Invidious Instance": "تبديل المثيل Invidious",
"Hide annotations": "إخفاء الملاحظات في الفيديو",
"Show annotations": "عرض الملاحظات في الفيديو",
"Hide annotations": "إخفاء الملاحظات فى الفيديو",
"Show annotations": "عرض الملاحظات فى الفيديو",
"Genre: ": "النوع: ",
"License: ": "التراخيص: ",
"Family friendly? ": "محتوى عائلي؟ ",
"Family friendly? ": "محتوى عائلى? ",
"Wilson score: ": "درجة ويلسون: ",
"Engagement: ": "نسبة المشاركة: ",
"Engagement: ": "نسبة المشاركة (عدد المشاهدات\\عدد الإعجابات): ",
"Whitelisted regions: ": "الدول المسموح فيها هذا الفيديو: ",
"Blacklisted regions: ": "الدول المحظور فيها هذا الفيديو: ",
"Blacklisted regions: ": "الدول الحظور فيها هذا الفيديو: ",
"Shared `x`": "شارك منذ `x`",
"`x` views": "`x` مشاهدات",
"Premieres in `x`": "يعرض فى `x`",
"Premieres `x`": "يعرض `x`",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "أهلًا! يبدو أن جافاسكريبت معطلٌ لديك. اضغط هنا لعرض التعليقات، وَضَع في اعتبارك أنها ستأخذ وقتًا أطول للتحميل.",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "اهلا! يبدو ان الجافاسكريبت معطلة. اضغط هنا لعرض التعليقات, ضع فى إعتبارك انها ستأخذ وقت اطول للعرض.",
"View YouTube comments": "عرض تعليقات اليوتيوب",
"View more comments on Reddit": "عرض المزيد من التعليقات على\\من موقع Reddit",
"View `x` comments": {
"([^.,0-9]|^)1([^.,0-9]|$)": "عرض `x` تعليقات",
"": "عرض `x` تعليقات"
},
"View `x` comments": "عرض `x` تعليقات",
"View Reddit comments": "عرض تعليقات ريدإت Reddit",
"Hide replies": "إخفاء الردود",
"Show replies": "عرض الردود",
"Incorrect password": "كلمة السر غير صحيحة",
"Quota exceeded, try again in a few hours": "تم تجاوز عدد المرات المسموح بها، حاول مجددًا بعد بضع ساعات",
"Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "غير قادر على تسجيل الدخول، تأكد من تشغيل المصادقة الثنائية 2FA.",
"Incorrect password": "الرقم السرى غير صحيح",
"Quota exceeded, try again in a few hours": "تم تجاوز عدد المرات المسموح بها, حاول مرة اخرى بعد عدة ساعات",
"Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "غير قادر على تسجيل الدخول, تأكد من تشغيل المصادقة الثنائية 2FA.",
"Invalid TFA code": "كود مصادقة ثنائية 2FA غير صحيح",
"Login failed. This may be because two-factor authentication is not turned on for your account.": "فشل تسجيل الدخول. قد يكون هذا بسبب أن المصادقة الثنائية 2FA معطلة في حسابك.",
"Login failed. This may be because two-factor authentication is not turned on for your account.": م يتم تسجيل الدخول. هذا ربما بسبب ان المصادقة الثنائية 2FA معطلة فى حسابك.",
"Wrong answer": "إجابة خاطئة",
"Erroneous CAPTCHA": "الكابتشا CAPTCHA غير صاحلة",
"CAPTCHA is a required field": "مكان الكابتشا CAPTCHA مطلوب",
"User ID is a required field": "مكان اسم المستخدم مطلوب",
"Password is a required field": "مكان كلمة السر مطلوب",
"Wrong username or password": "اسم المستخدم او كلمة السر غير صحيح",
"Please sign in using 'Log in with Google'": "الرجاء تسجيل الدخول باستخدام \"تسجيل الدخول باستخدام Google\"",
"Password cannot be empty": "لا يمكن أن تكون كلمة السر فارغة",
"Password cannot be longer than 55 characters": "يجب أن لا تتعدى كلمة السر 55 حرفًا",
"User ID is a required field": "مكان إسم المستخدم مطلوب",
"Password is a required field": "مكان الرقم السرى مطلوب",
"Wrong username or password": "إسم المستخدم او الرقم السرى غير صحيح",
"Please sign in using 'Log in with Google'": "الرجاء تسجيل الدخول 'تسجيل الدخول بواسطة جوجل'",
"Password cannot be empty": "الرقم السرى لايمكن ان يكون فارغ",
"Password cannot be longer than 55 characters": "الرقم السرى لا يتعدى 55 حرف",
"Please log in": "الرجاء تسجيل الدخول",
"Invidious Private Feed for `x`": "تغذية Invidious خاصة ل 'x'",
"Invidious Private Feed for `x`": "صفحة Invidious للمشتركين الخاصة\\مخفية لـ `x`",
"channel:`x`": "قناة:`x`",
"Deleted or invalid channel": "قناة ممسوحة او غير صالحة",
"This channel does not exist.": "هذه القناة غير موجودة.",
"This channel does not exist.": "القناة غير موجودة.",
"Could not get channel info.": "لم يستطع الحصول على معلومات القناة.",
"Could not fetch comments": "لم يتمكن من إحضار التعليقات",
"View `x` replies": "عرض `x` ردود",
"`x` ago": "`x` منذ",
"Load more": "عرض المزيد",
"Could not create mix.": "تعذر إنشاء مزيج.",
"`x` points": "`x` نقاط",
"Could not create mix.": "لم يستطع عمل خلط.",
"Empty playlist": "قائمة التشغيل فارغة",
"Not a playlist.": "قائمة التشغيل غير صالحة.",
"Playlist does not exist.": "قائمة التشغيل غير موجودة.",
"Could not pull trending pages.": "لم يستطع عرض الصفحات الراجئة.",
"Hidden field \"challenge\" is a required field": "مكان مخفي \"تحدي\" مكان مطلوب",
"Hidden field \"token\" is a required field": "مكان مخفي \"رمز\" مكان مطلوب",
"Erroneous challenge": "تحدي غير صالح",
"Erroneous token": مز مميز خاطئ",
"Hidden field \"challenge\" is a required field": "مكان مخفى \"تحدى\" مكان مطلوب",
"Hidden field \"token\" is a required field": "مكان مخفى \"رمز\" مكان مطلوب",
"Erroneous challenge": "تحدى غير صالح",
"Erroneous token": وز غير صالح",
"No such user": "مستخدم غير صالح",
"Token is expired, please try again": "الرمز منتهى الصلاحية، الرجاء المحاولة مرة اخرى",
"English": "إنجليزي",
"English (auto-generated)": "إنجليزي (تم إنشائه تلقائيًا)",
"Token is expired, please try again": "الرمز منتهى الصلاحية , الرجاء المحاولة مرة اخرى",
"English": "إنجليزى",
"English (auto-generated)": "إنجليزى (تم إنشائة تلقائى)",
"Afrikaans": "الأفريكانية",
"Albanian": "الألبانية",
"Amharic": "الأمهرية",
"Arabic": "العربية",
"Armenian": "الأرمينية",
"Azerbaijani": "أذربيجانية",
"Armenian": "الأرميني",
"Azerbaijani": "أذربيجان",
"Bangla": "البنغالية",
"Basque": "الباسكية",
"Basque": "الباسكي",
"Belarusian": "البيلاروسية",
"Bosnian": "البوسنية",
"Bulgarian": "البلغارية",
@ -303,13 +301,19 @@
"Yiddish": "اليديشية",
"Yoruba": "اليوروبا",
"Zulu": "الزولو",
"`x` years": "`x` سنوات",
"`x` months": "`x` شهور",
"`x` weeks": "`x` اسابيع",
"`x` days": "`x` ايام",
"`x` hours": "`x` ساعات",
"`x` minutes": "`x` دقائق",
"`x` seconds": "`x` ثوانى",
"Fallback comments: ": "التعليقات البديلة: ",
"Popular": "الأكثر شعبية",
"Search": "بحث",
"Top": "الأفضل",
"About": "حول",
"Rating: ": "التقييم: ",
"preferences_locale_label": "اللغة: ",
"Language: ": "اللغة: ",
"View as playlist": "عرض كا قائمة التشغيل",
"Default": "الكل",
"Music": "الاغانى",
@ -317,223 +321,16 @@
"News": "الأخبار",
"Movies": "الأفلام",
"Download": "نزّل",
"Download as: ": "نزله كـ: ",
"Download as: ": "نزّله كـ: ",
"%A %B %-d, %Y": "%A %-d %B %Y",
"(edited)": "(معدّل)",
"(edited)": "(تم تعديلة)",
"YouTube comment permalink": "رابط التعليق على اليوتيوب",
"permalink": "الرابط",
"`x` marked it with a ❤": "`x` أعجب بهذا",
"Audio mode": "الوضع الصوتي",
"`x` marked it with a ❤": "`x` اعجب بهذا",
"Audio mode": "الوضع الصوتى",
"Video mode": "وضع الفيديو",
"Videos": "الفيديوهات",
"Playlists": "قوائم التشغيل",
"Community": "المجتمع",
"search_filters_sort_option_relevance": "ملاؤم",
"search_filters_sort_option_rating": "تقييم",
"search_filters_sort_option_date": "التاريخ",
"search_filters_sort_option_views": "مشاهدات",
"search_filters_type_label": "نوع المحتوى",
"search_filters_duration_label": "المدة الزمنية",
"search_filters_features_label": "الميزات",
"search_filters_sort_label": "فرز",
"search_filters_date_option_hour": "آخر ساعة",
"search_filters_date_option_today": "اليوم",
"search_filters_date_option_week": "هذا الأسبوع",
"search_filters_date_option_month": "هذا الشهر",
"search_filters_date_option_year": "هذه السنة",
"search_filters_type_option_video": "فيديو",
"search_filters_type_option_channel": "قناة",
"search_filters_type_option_playlist": "قائمة التشغيل",
"search_filters_type_option_movie": "فيلم",
"search_filters_type_option_show": "عرض",
"search_filters_features_option_hd": "عالية الدقة",
"search_filters_features_option_subtitles": "ترجمات",
"search_filters_features_option_c_commons": "المشاع الإبداعي",
"search_filters_features_option_three_d": "ثلاثي الأبعاد",
"search_filters_features_option_live": "مباشر",
"search_filters_features_option_four_k": "4k",
"search_filters_features_option_location": "الأماكن",
"search_filters_features_option_hdr": "وضع التباين العالي",
"Current version: ": "الإصدار الحالي: ",
"next_steps_error_message": "بعد ذلك يجب أن تحاول: ",
"next_steps_error_message_refresh": "تحديث",
"next_steps_error_message_go_to_youtube": "انتقل إلى يوتيوب",
"search_filters_duration_option_short": "قصير (< 4 دقائق)",
"search_filters_duration_option_long": "طويل (> 20 دقيقة)",
"footer_source_code": "شفرة المصدر",
"footer_original_source_code": "كود المصدر الأصلي",
"footer_modfied_source_code": "شفرة المصدر المعدلة",
"adminprefs_modified_source_code_url_label": "URL إلى مستودع التعليمات البرمجية المصدرية المعدلة",
"footer_documentation": "التوثيق",
"footer_donate_page": "تبرّع",
"preferences_region_label": "بلد المحتوى: ",
"preferences_quality_dash_label": "جودة فيديو DASH المفضلة: ",
"preferences_quality_option_dash": "DASH (الجودة التلقائية)",
"preferences_quality_option_hd720": "HD720",
"preferences_quality_option_medium": "متوسطة",
"preferences_quality_option_small": "صغيرة",
"preferences_quality_dash_option_auto": "تلقائي",
"preferences_quality_dash_option_best": "الأفضل",
"preferences_quality_dash_option_worst": "أسوأ",
"preferences_quality_dash_option_4320p": "4320p",
"preferences_quality_dash_option_2160p": "2160p",
"preferences_quality_dash_option_1440p": "1440p",
"preferences_quality_dash_option_1080p": "1080p",
"preferences_quality_dash_option_720p": "720p",
"preferences_quality_dash_option_480p": "480p",
"preferences_quality_dash_option_360p": "360p",
"preferences_quality_dash_option_240p": "240p",
"preferences_quality_dash_option_144p": "144p",
"search_filters_features_option_purchased": "تم شراؤها",
"none": "لاشيء",
"videoinfo_started_streaming_x_ago": "بدأ البث منذ `x`",
"videoinfo_watch_on_youTube": "مشاهدة على يوتيوب",
"videoinfo_youTube_embed_link": "مضمن",
"videoinfo_invidious_embed_link": "رابط مضمن",
"user_created_playlists": "'x' إنشاء قوائم التشغيل",
"user_saved_playlists": "قوائم التشغيل المحفوظة 'x'",
"Video unavailable": "الفيديو غير متوفر",
"search_filters_features_option_three_sixty": "360°",
"download_subtitles": "ترجمات - 'x' (.vtt)",
"invidious": "الخيالي",
"preferences_save_player_pos_label": "حفظ موضع التشغيل: ",
"crash_page_you_found_a_bug": "يبدو أنك قد وجدت خطأً برمجيًّا في Invidious!",
"generic_videos_count_0": "لا فيديوهات",
"generic_videos_count_1": "فيديو واحد",
"generic_videos_count_2": "فيديوهين",
"generic_videos_count_3": "{{count}} فيديوهات",
"generic_videos_count_4": "{{count}} فيديو",
"generic_videos_count_5": "{{count}} فيديو",
"generic_subscribers_count_0": "لا مشتركين",
"generic_subscribers_count_1": "مشترك واحد",
"generic_subscribers_count_2": "مشتركان",
"generic_subscribers_count_3": "{{count}} مشتركين",
"generic_subscribers_count_4": "{{count}} مشترك",
"generic_subscribers_count_5": "{{count}} مشترك",
"generic_views_count_0": "لا مشاهدات",
"generic_views_count_1": "مشاهدة واحدة",
"generic_views_count_2": "مشاهدتان",
"generic_views_count_3": "{{count}} مشاهدات",
"generic_views_count_4": "{{count}} مشاهدة",
"generic_views_count_5": "{{count}} مشاهدة",
"generic_subscriptions_count_0": "لا اشتراكات",
"generic_subscriptions_count_1": "اشتراك واحد",
"generic_subscriptions_count_2": "اشتراكان",
"generic_subscriptions_count_3": "{{count}} اشتراكات",
"generic_subscriptions_count_4": "{{count}} اشتراك",
"generic_subscriptions_count_5": "{{count}} اشتراك",
"generic_playlists_count_0": "لا قوائم تشغيل",
"generic_playlists_count_1": "قائمة تشغيل واحدة",
"generic_playlists_count_2": "قائمتا تشغيل",
"generic_playlists_count_3": "{{count}} قوائم تشغيل",
"generic_playlists_count_4": "{{count}} قائمة تشغيل",
"generic_playlists_count_5": "{{count}} قائمة تشغيل",
"English (United States)": "الإنجليزية (الولايات المتحدة)",
"Indonesian (auto-generated)": "إندونيسي (مُنشأ تلقائيًا)",
"Interlingue": "إنترلينغوي",
"Italian (auto-generated)": "الإيطالية (مُنشأة تلقائيًا)",
"Spanish (auto-generated)": "الأسبانية (تم إنشاؤه تلقائيًا)",
"crash_page_before_reporting": "قبل الإبلاغ عن خطأ، تأكد من وجود:",
"French (auto-generated)": "الفرنسية (مُنشأة تلقائيًا)",
"Portuguese (auto-generated)": "البرتغالية (تم إنشاؤه تلقائيًا)",
"Turkish (auto-generated)": "التركية (تم إنشاؤها تلقائيًا)",
"crash_page_refresh": "حاول <a href=\"`x`\"> تحديث الصفحة </a>",
"crash_page_switch_instance": "حاول <a href=\"`x`\"> استخدام مثيل آخر </a>",
"Korean (auto-generated)": "كوري (تم إنشاؤه تلقائيًا)",
"Spanish (Mexico)": "الإسبانية (المكسيك)",
"Vietnamese (auto-generated)": "فيتنامي (تم إنشاؤه تلقائيًا)",
"crash_page_report_issue": "إذا لم يساعد أي مما سبق، يرجى فتح <a href=\"`x`\"> مشكلة جديدة على GitHub </a> (ويفضل أن يكون باللغة الإنجليزية) وتضمين النص التالي في رسالتك (لا تترجم هذا النص):",
"crash_page_read_the_faq": "قراءة <a href=\"`x`\"> الأسئلة المتكررة (الأسئلة الشائعة) </a>",
"preferences_watch_history_label": "تمكين سجل المشاهدة: ",
"English (United Kingdom)": "الإنجليزية (المملكة المتحدة)",
"Cantonese (Hong Kong)": "الكانتونية (هونغ كونغ)",
"Chinese": "الصينية",
"Chinese (China)": "الصينية (الصين)",
"Chinese (Hong Kong)": "الصينية (هونج كونج)",
"Chinese (Taiwan)": "الصينية (تايوان)",
"Dutch (auto-generated)": "هولندي (تم إنشاؤه تلقائيًا)",
"German (auto-generated)": "ألماني (تم إنشاؤه تلقائيًا)",
"Japanese (auto-generated)": "اليابانية (مُنشأة تلقائيًا)",
"Portuguese (Brazil)": "البرتغالية (البرازيل)",
"Russian (auto-generated)": "الروسية (منشأة تلقائيا)",
"Spanish (Spain)": "الإسبانية (إسبانيا)",
"crash_page_search_issue": "بحثت عن <a href=\"`x`\"> المشكلات الموجودة على GitHub </a>",
"search_filters_title": "معامل الفرز",
"search_message_no_results": "لا توجد نتائج.",
"search_message_change_filters_or_query": "حاول توسيع استعلام البحث و / أو تغيير عوامل التصفية.",
"search_filters_date_label": "تاريخ الرفع",
"generic_count_weeks_0": "{{count}} أسبوع",
"generic_count_weeks_1": "{{count}} أسبوع",
"generic_count_weeks_2": "{{count}} أسبوع",
"generic_count_weeks_3": "{{count}} أسبوع",
"generic_count_weeks_4": "{{count}} أسابيع",
"generic_count_weeks_5": "{{count}} أسبوع",
"Popular enabled: ": "تم تمكين الشعبية: ",
"search_filters_duration_option_medium": "متوسط (4-20 دقيقة)",
"search_filters_date_option_none": "أي تاريخ",
"search_filters_type_option_all": "أي نوع",
"search_filters_features_option_vr180": "VR180",
"generic_count_minutes_0": "{{count}} دقيقة",
"generic_count_minutes_1": "{{count}} دقيقة",
"generic_count_minutes_2": "{{count}} دقيقة",
"generic_count_minutes_3": "{{count}} دقيقة",
"generic_count_minutes_4": "{{count}} دقائق",
"generic_count_minutes_5": "{{count}} دقيقة",
"generic_count_hours_0": "{{count}} ساعة",
"generic_count_hours_1": "{{count}} ساعة",
"generic_count_hours_2": "{{count}} ساعة",
"generic_count_hours_3": "{{count}} ساعة",
"generic_count_hours_4": "{{count}} ساعات",
"generic_count_hours_5": "{{count}} ساعة",
"comments_view_x_replies_0": "عرض رد {{count}}",
"comments_view_x_replies_1": "عرض رد {{count}}",
"comments_view_x_replies_2": "عرض رد {{count}}",
"comments_view_x_replies_3": "عرض رد {{count}}",
"comments_view_x_replies_4": "عرض الردود {{count}}",
"comments_view_x_replies_5": "عرض رد {{count}}",
"search_message_use_another_instance": " يمكنك أيضًا البحث عن <a href=\"`x`\"> في مثيل آخر </a>.",
"comments_points_count_0": "{{count}} نقطة",
"comments_points_count_1": "{{count}} نقطة",
"comments_points_count_2": "{{count}} نقطة",
"comments_points_count_3": "{{count}} نقطة",
"comments_points_count_4": "{{count}} نقاط",
"comments_points_count_5": "{{count}} نقطة",
"generic_count_years_0": "{{count}} السنة",
"generic_count_years_1": "{{count}} السنة",
"generic_count_years_2": "{{count}} السنة",
"generic_count_years_3": "{{count}} السنة",
"generic_count_years_4": "{{count}} سنوات",
"generic_count_years_5": "{{count}} السنة",
"tokens_count_0": "الرمز المميز {{count}}",
"tokens_count_1": "الرمز المميز {{count}}",
"tokens_count_2": "الرمز المميز {{count}}",
"tokens_count_3": "الرمز المميز {{count}}",
"tokens_count_4": "الرموز المميزة {{count}}",
"tokens_count_5": "الرمز المميز {{count}}",
"search_filters_apply_button": "تطبيق الفلاتر المحددة",
"search_filters_duration_option_none": "أي مدة",
"subscriptions_unseen_notifs_count_0": "{{count}} إشعار غير مرئي",
"subscriptions_unseen_notifs_count_1": "{{count}} إشعار غير مرئي",
"subscriptions_unseen_notifs_count_2": "{{count}} إشعار غير مرئي",
"subscriptions_unseen_notifs_count_3": "{{count}} إشعار غير مرئي",
"subscriptions_unseen_notifs_count_4": "{{count}} إشعارات غير مرئية",
"subscriptions_unseen_notifs_count_5": "{{count}} إشعار غير مرئي",
"generic_count_days_0": "{{count}} يوم",
"generic_count_days_1": "{{count}} يوم",
"generic_count_days_2": "{{count}} يوم",
"generic_count_days_3": "{{count}} يوم",
"generic_count_days_4": "{{count}} أيام",
"generic_count_days_5": "{{count}} يوم",
"generic_count_months_0": "{{count}} شهر",
"generic_count_months_1": "{{count}} شهر",
"generic_count_months_2": "{{count}} شهر",
"generic_count_months_3": "{{count}} شهر",
"generic_count_months_4": "{{count}} شهور",
"generic_count_months_5": "{{count}} شهر",
"generic_count_seconds_0": "{{count}} ثانية",
"generic_count_seconds_1": "{{count}} ثانية",
"generic_count_seconds_2": "{{count}} ثانية",
"generic_count_seconds_3": "{{count}} ثانية",
"generic_count_seconds_4": "{{count}} ثوانٍ",
"generic_count_seconds_5": "{{count}} ثانية"
}
"Current version: ": "الإصدار الحالي: "
}

View File

@ -1,97 +0,0 @@
{
"Subscribe": "সাবস্ক্রাইব",
"View channel on YouTube": "ইউটিউবে চ্যানেল দেখুন",
"View playlist on YouTube": "ইউটিউবে প্লেলিস্ট দেখুন",
"newest": "সর্ব-নতুন",
"oldest": "পুরানতম",
"popular": "জনপ্রিয়",
"last": "শেষটা",
"Next page": "পরের পৃষ্ঠা",
"Previous page": "আগের পৃষ্ঠা",
"Clear watch history?": "দেখার ইতিহাস সাফ করবেন?",
"New password": "নতুন পাসওয়ার্ড",
"New passwords must match": "নতুন পাসওয়ার্ড অবশ্যই মিলতে হবে",
"Cannot change password for Google accounts": "গুগল অ্যাকাউন্টগুলোর জন্য পাসওয়ার্ড পরিবর্তন করা যায় না",
"Authorize token?": "টোকেন অনুমোদন করবেন?",
"Authorize token for `x`?": "`x` -এর জন্য টোকেন অনুমোদন?",
"Yes": "হ্যাঁ",
"No": "না",
"Import and Export Data": "তথ্য আমদানি ও রপ্তানি",
"Import": "আমদানি",
"Import Invidious data": "ইনভিডিয়াস তথ্য আমদানি",
"Import YouTube subscriptions": "ইউটিউব সাবস্ক্রিপশন আনুন",
"Import FreeTube subscriptions (.db)": "ফ্রিটিউব সাবস্ক্রিপশন (.db) আনুন",
"Import NewPipe subscriptions (.json)": "নতুন পাইপ সাবস্ক্রিপশন আনুন (.json)",
"Import NewPipe data (.zip)": "নিউপাইপ তথ্য আনুন (.zip)",
"Export": "তথ্য বের করুন",
"Export subscriptions as OPML": "সাবস্ক্রিপশন OPML হিসাবে আনুন",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "OPML-এ সাবস্ক্রিপশন বের করুন(নিউ পাইপ এবং ফ্রিউটিউব এর জন্য)",
"Export data as JSON": "JSON হিসাবে তথ্য বের করুন",
"Delete account?": "অ্যাকাউন্ট মুছে ফেলবেন?",
"History": "ইতিহাস",
"An alternative front-end to YouTube": "ইউটিউবের একটি বিকল্পস্বরূপ সম্মুখ-প্রান্ত",
"JavaScript license information": "জাভাস্ক্রিপ্ট লাইসেন্সের তথ্য",
"source": "সূত্র",
"Log in": "লগ ইন",
"Log in/register": "লগ ইন/রেজিস্টার",
"Log in with Google": "গুগল দিয়ে লগ ইন করুন",
"User ID": "ইউজার আইডি",
"Password": "পাসওয়ার্ড",
"Time (h:mm:ss):": "সময় (ঘণ্টা:মিনিট:সেকেন্ড):",
"Text CAPTCHA": "টেক্সট ক্যাপচা",
"Image CAPTCHA": "চিত্র ক্যাপচা",
"Sign In": "সাইন ইন",
"Register": "নিবন্ধন",
"E-mail": "ই-মেইল",
"Google verification code": "গুগল যাচাইকরণ কোড",
"Preferences": "পছন্দসমূহ",
"preferences_category_player": "প্লেয়ারের পছন্দসমূহ",
"preferences_video_loop_label": "সর্বদা লুপ: ",
"preferences_autoplay_label": "স্বয়ংক্রিয় চালু: ",
"preferences_continue_label": "ডিফল্টভাবে পরবর্তী চালাও: ",
"preferences_continue_autoplay_label": "পরবর্তী ভিডিও স্বয়ংক্রিয়ভাবে চালাও: ",
"preferences_listen_label": "সহজাতভাবে শোনো: ",
"preferences_local_label": "ভিডিও প্রক্সি করো: ",
"preferences_speed_label": "সহজাত গতি: ",
"preferences_quality_label": "পছন্দের ভিডিও মান: ",
"preferences_volume_label": "প্লেয়ার শব্দের মাত্রা: ",
"LIVE": "লাইভ",
"Shared `x` ago": "`x` আগে শেয়ার করা হয়েছে",
"Unsubscribe": "আনসাবস্ক্রাইব",
"generic_views_count": "{{count}}জন দেখেছে",
"generic_views_count_plural": "{{count}}জন দেখেছে",
"generic_videos_count": "{{count}}টি ভিডিও",
"generic_videos_count_plural": "{{count}}টি ভিডিও",
"generic_subscribers_count": "{{count}}জন অনুসরণকারী",
"generic_subscribers_count_plural": "{{count}}জন অনুসরণকারী",
"preferences_watch_history_label": "দেখার ইতিহাস চালু করো: ",
"preferences_quality_option_dash": "ড্যাশ (সময়োপযোগী মান)",
"preferences_quality_dash_option_auto": "স্বয়ংক্রিয়",
"preferences_quality_dash_option_best": "সেরা",
"preferences_quality_dash_option_worst": "মন্দতম",
"preferences_quality_dash_option_4320p": "৪৩২০পি",
"preferences_quality_dash_option_2160p": "২১৬০পি",
"preferences_quality_dash_option_1440p": "১৪৪০পি",
"preferences_quality_dash_option_480p": "৪৮০পি",
"preferences_quality_dash_option_360p": "৩৬০পি",
"preferences_quality_dash_option_240p": "২৪০পি",
"preferences_quality_dash_option_144p": "১৪৪পি",
"preferences_comments_label": "সহজাত মন্তব্য: ",
"youtube": "ইউটিউব",
"Fallback captions: ": "বিকল্প উপাখ্যান: ",
"preferences_related_videos_label": "সম্পর্কিত ভিডিও দেখাও: ",
"preferences_annotations_label": "সহজাতভাবে টীকা দেখাও ",
"preferences_quality_option_hd720": "উচ্চ৭২০",
"preferences_quality_dash_label": "পছন্দের ড্যাশ ভিডিও মান: ",
"preferences_captions_label": "সহজাত উপাখ্যান: ",
"generic_playlists_count": "{{count}}টি চালুতালিকা",
"generic_playlists_count_plural": "{{count}}টি চালুতালিকা",
"reddit": "রেডিট",
"invidious": "ইনভিডিয়াস",
"generic_subscriptions_count": "{{count}}টি অনুসরণ",
"generic_subscriptions_count_plural": "{{count}}টি অনুসরণ",
"preferences_quality_option_medium": "মধ্যম",
"preferences_quality_option_small": "ছোট",
"preferences_quality_dash_option_1080p": "১০৮০পি",
"preferences_quality_dash_option_720p": "৭২০পি"
}

View File

@ -1,61 +0,0 @@
{
"LIVE": "লাইভ",
"Shared `x` ago": "`x` আগে শেয়ার করা হয়েছে",
"Unsubscribe": "আনসাবস্ক্রাইব",
"Subscribe": "সাবস্ক্রাইব",
"View channel on YouTube": "ইউটিউবে চ্যানেল দেখুন",
"View playlist on YouTube": "ইউটিউবে প্লেলিস্ট দেখুন",
"newest": "সর্ব-নতুন",
"oldest": "পুরানতম",
"popular": "জনপ্রিয়",
"last": "শেষটা",
"Next page": "পরের পৃষ্ঠা",
"Previous page": "আগের পৃষ্ঠা",
"Clear watch history?": "দেখার ইতিহাস সাফ করবেন?",
"New password": "নতুন পাসওয়ার্ড",
"New passwords must match": "নতুন পাসওয়ার্ড অবশ্যই মিলতে হবে",
"Cannot change password for Google accounts": "গুগল অ্যাকাউন্টগুলোর জন্য পাসওয়ার্ড পরিবর্তন করা যায় না",
"Authorize token?": "টোকেন অনুমোদন করবেন?",
"Authorize token for `x`?": "`x` -এর জন্য টোকেন অনুমোদন?",
"Yes": "হ্যাঁ",
"No": "না",
"Import and Export Data": "তথ্য আমদানি ও রপ্তানি",
"Import": "আমদানি",
"Import Invidious data": "ইনভিডিয়াস তথ্য আমদানি",
"Import YouTube subscriptions": "ইউটিউব সাবস্ক্রিপশন আনুন",
"Import FreeTube subscriptions (.db)": "ফ্রিটিউব সাবস্ক্রিপশন (.db) আনুন",
"Import NewPipe subscriptions (.json)": "নতুন পাইপ সাবস্ক্রিপশন আনুন (.json)",
"Import NewPipe data (.zip)": "নিউপাইপ তথ্য আনুন (.zip)",
"Export": "তথ্য বের করুন",
"Export subscriptions as OPML": "সাবস্ক্রিপশন OPML হিসাবে আনুন",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "OPML-এ সাবস্ক্রিপশন বের করুন(নিউ পাইপ এবং ফ্রিউটিউব এর জন্য)",
"Export data as JSON": "JSON হিসাবে তথ্য বের করুন",
"Delete account?": "অ্যাকাউন্ট মুছে ফেলবেন?",
"History": "ইতিহাস",
"An alternative front-end to YouTube": "ইউটিউবের একটি বিকল্পস্বরূপ সম্মুখ-প্রান্ত",
"JavaScript license information": "জাভাস্ক্রিপ্ট লাইসেন্সের তথ্য",
"source": "সূত্র",
"Log in": "লগ ইন",
"Log in/register": "লগ ইন/রেজিস্টার",
"Log in with Google": "গুগল দিয়ে লগ ইন করুন",
"User ID": "ইউজার আইডি",
"Password": "পাসওয়ার্ড",
"Time (h:mm:ss):": "সময় (ঘণ্টা:মিনিট:সেকেন্ড):",
"Text CAPTCHA": "টেক্সট ক্যাপচা",
"Image CAPTCHA": "চিত্র ক্যাপচা",
"Sign In": "সাইন ইন",
"Register": "নিবন্ধন",
"E-mail": "ই-মেইল",
"Google verification code": "গুগল যাচাইকরণ কোড",
"Preferences": "পছন্দসমূহ",
"preferences_category_player": "প্লেয়ারের পছন্দসমূহ",
"preferences_video_loop_label": "সর্বদা লুপ: ",
"preferences_autoplay_label": "স্বয়ংক্রিয় চালু: ",
"preferences_continue_label": "ডিফল্টভাবে পরবর্তী চালাও: ",
"preferences_continue_autoplay_label": "পরবর্তী ভিডিও স্বয়ংক্রিয়ভাবে চালাও: ",
"preferences_listen_label": "সহজাতভাবে শোনো: ",
"preferences_local_label": "ভিডিও প্রক্সি করো: ",
"preferences_speed_label": "সহজাত গতি: ",
"preferences_quality_label": "পছন্দের ভিডিও মান: ",
"preferences_volume_label": "প্লেয়ার শব্দের মাত্রা: "
}

View File

@ -1,103 +0,0 @@
{
"oldest": "més antic",
"Yes": "Sí",
"preferences_quality_label": "Qualitat de vídeo preferida: ",
"newest": "més nou",
"No": "No",
"Google verification code": "Codi de verificació de Google",
"User ID": "ID d'usuari",
"Preferences": "Preferències",
"Dark mode: ": "Mode fosc: ",
"dark": "fosc",
"light": "clar",
"published": "publicat",
"published - reverse": "publicat - invers",
"alphabetically": "alfabèticament",
"alphabetically - reverse": "alfabèticament - invers",
"channel name - reverse": "nom del canal - invers",
"preferences_category_data": "Preferències de dades",
"Delete account": "Elimina compte",
"Save preferences": "Guarda preferències",
"Private": "Privat",
"Show more": "Mostra'n més",
"Show less": "Mostra'n menys",
"Hide replies": "Amaga respostes",
"Arabic": "Àrab",
"Armenian": "Armeni",
"Basque": "Basc",
"Filipino": "Filipí",
"Finnish": "Finès",
"German": "Alemany",
"Greek": "Grec",
"Hungarian": "Hongarès",
"Icelandic": "Islandès",
"Italian": "Italià",
"Japanese": "Japonès",
"Korean": "Coreà",
"Kurdish": "Kurd",
"Lithuanian": "Lituà",
"Luxembourgish": "Luxemburguès",
"Macedonian": "Macedoni",
"Polish": "Polonès",
"Portuguese": "Portuguès",
"Romanian": "Romanès",
"Russian": "Rus",
"Serbian": "Serbi",
"Spanish (Latin America)": "Castellà (Amèrica llatina)",
"Turkish": "Turc",
"Ukrainian": "Ucraïnès",
"preferences_locale_label": "Idioma: ",
"Gaming": "Jocs",
"Movies": "Películes",
"Download": "Descarrega",
"Download as: ": "Descarrega com: ",
"Videos": "Vídeos",
"search_filters_type_label": "Tipus",
"search_filters_duration_label": "Duració",
"search_filters_sort_label": "Ordena per",
"search_filters_date_option_week": "Aquesta setmana",
"search_filters_date_option_month": "Aquest mes",
"search_filters_date_option_year": "Aquest any",
"search_filters_type_option_video": "Vídeo",
"search_filters_type_option_channel": "Canal",
"search_filters_duration_option_short": "Curt (< 4 minuts)",
"search_filters_duration_option_long": "Llarg (> 20 minuts)",
"Current version: ": "Versió actual: ",
"Malay": "Malai",
"Persian": "Persa",
"Slovak": "Eslovac",
"Search": "Busca",
"Show annotations": "Mostra anotacions",
"preferences_region_label": "País del contingut: ",
"preferences_sort_label": "Ordena vídeos per: ",
"Import/export": "Importa/exporta",
"channel name": "nom del canal",
"Title": "Títol",
"Belarusian": "Bielorús",
"Enable web notifications": "Activa notificacions web",
"search": "busca",
"Catalan": "Català",
"Croatian": "Croat",
"preferences_category_admin": "Preferències d'administrador",
"Hide annotations": "Amaga anotacions",
"Show replies": "Mostra respostes",
"Bulgarian": "Búlgar",
"Albanian": "Albanès",
"French": "Francès",
"Irish": "Irlandès",
"Maltese": "Maltès",
"Danish": "Danès",
"Galician": "Gallec",
"Hebrew": "Hebreu",
"Indonesian": "Indonesi",
"Spanish": "Castellà",
"Vietnamese": "Vietnamita",
"News": "Notícies",
"search_filters_type_option_show": "Mostra",
"footer_documentation": "Documentació",
"Thai": "Tailandès",
"Music": "Música",
"search_filters_sort_option_relevance": "Rellevància",
"search_filters_date_option_hour": "Última hora",
"search_filters_date_option_today": "Avui"
}

View File

@ -1,491 +0,0 @@
{
"LIVE": "ŽIVĚ",
"Shared `x` ago": "Zveřejněno před `x`",
"Unsubscribe": "Odhlásit odběr",
"Subscribe": "Odebírat",
"View channel on YouTube": "Otevřít kanál na YouTube",
"View playlist on YouTube": "Zobrazit playlist na YouTube",
"newest": "nejnovější",
"oldest": "nejstarší",
"popular": "populární",
"last": "poslední",
"Next page": "Další strana",
"Previous page": "Předchozí strana",
"Clear watch history?": "Smazat historii?",
"New password": "Nové heslo",
"New passwords must match": "Hesla se musí schodovat",
"Cannot change password for Google accounts": "Nelze změnit heslo pro účty Google",
"Authorize token?": "Autorizovat token?",
"Authorize token for `x`?": "Autorizovat token pro `x`?",
"Yes": "Ano",
"No": "Ne",
"Import and Export Data": "Import a export dat",
"Import": "Importovat",
"Import Invidious data": "Importovat JSON údaje Invidious",
"Import YouTube subscriptions": "Importovat odběry z YouTube/OPML",
"Import FreeTube subscriptions (.db)": "Importovat odběry z FreeTube (.db)",
"Import NewPipe subscriptions (.json)": "Importovat odběry z NewPipe (.json)",
"Import NewPipe data (.zip)": "Importovat údeje z NewPipe (.zip)",
"Export": "Exportovat",
"Export subscriptions as OPML": "Exportovat odběry jako OPML",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Exportovat údaje jako OPML (na NewPipe a FreeTube)",
"Export data as JSON": "Exportovat data Invidious jako JSON",
"Delete account?": "Smazat účet?",
"History": "Historie",
"An alternative front-end to YouTube": "Alternativní front-end pro YouTube",
"JavaScript license information": "Informace o licenci JavaScript",
"source": "zdrojový kód",
"Log in": "Přihlásit se",
"Log in/register": "Přihlásit se/vytvořit účet",
"Log in with Google": "Přihlásit se s Googlem",
"User ID": "ID uživatele",
"Password": "Heslo",
"Time (h:mm:ss):": "Čas (h:mm:ss):",
"Text CAPTCHA": "Textové CAPTCHA",
"Image CAPTCHA": "Obrázkové CAPTCHA",
"Sign In": "Přihlásit se",
"Register": "Vytvořit účet",
"E-mail": "E-mail",
"Google verification code": "Verifikační číslo Google",
"Preferences": "Nastavení",
"preferences_category_player": "Nastavení přehravače",
"preferences_video_loop_label": "Vždy opakovat: ",
"preferences_autoplay_label": "Automatické přehrávání: ",
"preferences_continue_label": "Automaticky přehrát další: ",
"preferences_continue_autoplay_label": "Automaticky přehrát další video: ",
"preferences_listen_label": "Poslouchat ve výchozím nastavení: ",
"preferences_local_label": "Video přes proxy: ",
"preferences_speed_label": "Výchozí rychlost: ",
"preferences_quality_label": "Preferovaná kvalita videa: ",
"preferences_volume_label": "Hlasitost přehrávače: ",
"preferences_comments_label": "Předpřipravené komentáře: ",
"youtube": "YouTube",
"reddit": "Reddit",
"preferences_captions_label": "Výchozí titulky: ",
"Fallback captions: ": "Záložní titulky: ",
"preferences_related_videos_label": "Zobrazit podobné videa: ",
"preferences_annotations_label": "Zobrazovat poznámky ve výchozím nastavení: ",
"preferences_extend_desc_label": "Rozšířit automaticky popis u videa: ",
"preferences_category_visual": "Nastavení vzhledu",
"preferences_player_style_label": "Styl přehrávače ",
"Dark mode: ": "Tmavý režim ",
"preferences_dark_mode_label": "Vzhled: ",
"dark": "tmavý",
"light": "světlý",
"preferences_thin_mode_label": "Kompaktní režim: ",
"preferences_category_subscription": "Nastavení předplatných",
"preferences_annotations_subscribed_label": "Ve výchozím nastavení zobrazovat poznámky u odebíraných kanálů: ",
"Redirect homepage to feed: ": "Přesměrovávat domovskou stránku na informační kanál: ",
"preferences_max_results_label": "Počet videí zobrazovaných v informačním kanále: ",
"preferences_sort_label": "Roztřídit videa podle: ",
"published": "publikováno",
"published - reverse": "podle publikování - obrátit",
"alphabetically": "podle abecedy",
"alphabetically - reverse": "podle abecedy - převrátit",
"channel name": "název kanálu",
"channel name - reverse": "podle jména kanálu - převrátit",
"Only show latest video from channel: ": "Jenom zobrazit nejnovjejší video z kanálu: ",
"Only show latest unwatched video from channel: ": "Zobrazit jen nejnovější nezhlédnuté video z daného kanálu: ",
"preferences_unseen_only_label": "Zobrazit jen již nezhlédnuté: ",
"preferences_notifications_only_label": "Zobrazit pouze upozornění (pokud nějaká jsou): ",
"Enable web notifications": "Povolit webová upozornění",
"`x` uploaded a video": "`x` nahrál(a) video",
"`x` is live": "`x` je živě",
"preferences_category_data": "Nastavení dat",
"Clear watch history": "Smazat historii",
"Import/export data": "Importovat/exportovat data",
"Change password": "Změnit heslo",
"Manage subscriptions": "Spravovat odebírané kanály",
"Manage tokens": "Spravovat tokeny",
"Watch history": "Historie sledování",
"Delete account": "Smazat účet",
"preferences_category_admin": "Administrátorská nastavení",
"preferences_default_home_label": "Základní domovská stránka: ",
"preferences_feed_menu_label": "Menu doporučených: ",
"CAPTCHA enabled: ": "CAPTCHA povolena: ",
"Login enabled: ": "Přihlášení povoleno: ",
"Registration enabled: ": "Registrace povolena ",
"Report statistics: ": "Oznámit statistiky: ",
"Save preferences": "Uložit nastavení",
"Subscription manager": "Správa odběrů",
"Token manager": "Správa tokenů",
"Token": "Token",
"Import/export": "Importovat/exportovat",
"unsubscribe": "odhlásit odběr",
"revoke": "vrátit zpět",
"Subscriptions": "Odběry",
"search": "hledat",
"Log out": "Odhlásit se",
"Source available here.": "Zdrojový kód dostupný zde.",
"View JavaScript license information.": "Zobrazit informace o licenci JavaScript .",
"View privacy policy.": "Zobrazit zásady ochrany osobních údajů.",
"Trending": "Trendy",
"Public": "Veřejné",
"Unlisted": "Neveřejné",
"Private": "Soukromé",
"View all playlists": "Zobrazit všechny playlisty",
"Updated `x` ago": "Aktualizováno před `x`",
"Delete playlist `x`?": "Smazat playlist `x`?",
"Delete playlist": "Smazat playlist",
"Create playlist": "Vytvořit playlist",
"Title": "Název",
"Editing playlist `x`": "Upravování playlistu `x`",
"Show more": "Zobrazit více",
"Show less": "Zobrazit méně",
"Watch on YouTube": "Sledovat na YouTube",
"Hide annotations": "Skrýt poznámky",
"Show annotations": "Zobrazit poznámky",
"Genre: ": "Žánr: ",
"License: ": "Licence: ",
"Family friendly? ": "Vhodné pro rodiny? ",
"Engagement: ": "Zapojení: ",
"English": "Angličtina",
"English (auto-generated)": "Angličtina (automaticky generováno)",
"Afrikaans": "Afrikánština",
"Albanian": "Albánština",
"Amharic": "Amharština",
"Arabic": "Arabština",
"Armenian": "Arménština",
"Azerbaijani": "Azerbajdžánština",
"Bangla": "Bengálština",
"Basque": "Baskičtina",
"Belarusian": "Běloruština",
"Bosnian": "Bosenština",
"Bulgarian": "Bulharština",
"Burmese": "Barmština",
"Catalan": "Katalánština",
"Cebuano": "Cebuánština",
"Chinese (Simplified)": "Čínština (zjednodušená)",
"Chinese (Traditional)": "Čínština (tradiční)",
"Corsican": "Korsičtina",
"Croatian": "Chorvatština",
"Czech": "Čeština",
"Danish": "Dánština",
"Dutch": "Nizozemština",
"Esperanto": "Esperanto",
"Estonian": "Estonština",
"Filipino": "Filipínština",
"Finnish": "Finština",
"French": "Francouzština",
"Galician": "Galicijština",
"Georgian": "Gruzínština",
"German": "Němčina",
"Greek": "Řečtina",
"Gujarati": "Gudžarátština",
"Haitian Creole": "Haitská kreolština",
"Hausa": "Hauština",
"Hawaiian": "Havajština",
"Hebrew": "Hebrejština",
"Hindi": "Hindština",
"Hmong": "Hmongština",
"Hungarian": "Maďarština",
"Icelandic": "Islandština",
"Igbo": "Igboština",
"Indonesian": "Indonéština",
"Irish": "Irština",
"Italian": "Italština",
"Japanese": "Japonština",
"Javanese": "Javánština",
"Kannada": "Kannadština",
"Kazakh": "Kazaština",
"Khmer": "Khmerština",
"Korean": "Korejština",
"Kurdish": "Kurdština",
"Kyrgyz": "Kyrgyzština",
"Lao": "Laoština",
"Latin": "Latina",
"Latvian": "Lotyština",
"Lithuanian": "Litevština",
"Luxembourgish": "Lucemburština",
"Macedonian": "Makedonština",
"Malagasy": "Malgaština",
"Malay": "Malajština",
"Malayalam": "Malajálamština",
"Maltese": "Maltština",
"Maori": "Maorština",
"Marathi": "Maráthština",
"Mongolian": "Mongolština",
"Nepali": "Nepálština",
"Norwegian Bokmål": "Norština Bokmål",
"Nyanja": "Čičevština",
"Pashto": "Paštština",
"Persian": "Perština",
"Polish": "Polština",
"Portuguese": "Portugalština",
"Punjabi": "Paňdžábština",
"Romanian": "Rumunština",
"Russian": "Ruština",
"Samoan": "Samojština",
"Scottish Gaelic": "Skotská gaelština",
"Serbian": "Srbština",
"Shona": "Shona",
"Sindhi": "Sindhština",
"Sinhala": "Sinhálština",
"Slovak": "Slovenština",
"Slovenian": "Slovinština",
"Somali": "Somálština",
"Southern Sotho": "Sesothština",
"Spanish": "Španělština",
"Spanish (Latin America)": "Španělština (Latinská Amerika)",
"Sundanese": "Sundština",
"Swahili": "Svahilština",
"Swedish": "Švédština",
"Tajik": "Tádžičtina",
"Tamil": "Tamilština",
"Telugu": "Telugština",
"Thai": "Thajština",
"Turkish": "Turečtina",
"Ukrainian": "Ukrajinština",
"Urdu": "Urdština",
"Uzbek": "Uzbečtina",
"Vietnamese": "Vietnamština",
"Welsh": "Velština",
"Western Frisian": "Západofríština",
"Xhosa": "Xhoština",
"Yiddish": "Jidiš",
"Yoruba": "Jorubština",
"Zulu": "Zuluština",
"Popular": "Populární",
"About": "Informace",
"Rating: ": "Hodnocení: ",
"preferences_locale_label": "Jazyk: ",
"Default": "Výchozí",
"Music": "Hudba",
"Gaming": "Hry",
"News": "Zprávy",
"Movies": "Filmy",
"Download": "Stáhnout",
"Download as: ": "Stáhnout jako: ",
"(edited)": "(upraveno)",
"`x` marked it with a ❤": "`x` to označil(a) se ❤",
"Audio mode": "Audiový režim",
"Video mode": "Videový režim",
"Videos": "Videa",
"Community": "Komunita",
"search_filters_sort_option_rating": "Hodnocení",
"search_filters_sort_option_date": "Datum nahrání",
"search_filters_sort_option_views": "Počet zhlédnutí",
"search_filters_duration_label": "Délka",
"search_filters_date_option_hour": "Poslední hodina",
"search_filters_date_option_today": "Dnes",
"search_filters_date_option_week": "Tento týden",
"search_filters_date_option_month": "Tento měsíc",
"search_filters_date_option_year": "Tento rok",
"search_filters_type_option_video": "Video",
"search_filters_type_option_channel": "Kanál",
"search_filters_type_option_playlist": "Playlist",
"search_filters_type_option_movie": "Film",
"search_filters_type_option_show": "Seriál",
"search_filters_features_option_hd": "HD",
"search_filters_features_option_subtitles": "Titulky",
"search_filters_features_option_c_commons": "Creative Commons",
"search_filters_features_option_three_d": "3D",
"search_filters_features_option_live": "Živě",
"search_filters_features_option_four_k": "4K",
"search_filters_features_option_location": "Umístění",
"search_filters_features_option_hdr": "HDR",
"generic_count_days_0": "{{count}} dnem",
"generic_count_days_1": "{{count}} dny",
"generic_count_days_2": "{{count}} dny",
"generic_count_hours_0": "{{count}} hodinou",
"generic_count_hours_1": "{{count}} hodinami",
"generic_count_hours_2": "{{count}} hodinami",
"crash_page_refresh": "zkusili <a href=\"`x`\">obnovit stránku</a>",
"crash_page_switch_instance": "zkusili <a href=\"`x`\">použít jinou instanci</a>",
"preferences_vr_mode_label": "Interaktivní 360-stupňová videa (vyžaduje WebGL): ",
"English (United Kingdom)": "Angličtina (Spojené království)",
"Chinese (China)": "Čínština (Čína)",
"Chinese (Hong Kong)": "Čínština (Hong Kong)",
"Chinese (Taiwan)": "Čínština (Taiwan)",
"Portuguese (auto-generated)": "Portugalština (automaticky generováno)",
"Spanish (auto-generated)": "Španělština (automaticky generováno)",
"Spanish (Mexico)": "Španělština (Mexiko)",
"Spanish (Spain)": "Španělština (Španělsko)",
"generic_count_years_0": "{{count}} rokem",
"generic_count_years_1": "{{count}} lety",
"generic_count_years_2": "{{count}} lety",
"Fallback comments: ": "Záložní komentáře: ",
"Search": "Hledat",
"Top": "Nejlepší",
"Playlists": "Playlisty",
"videoinfo_started_streaming_x_ago": "Stream spuštěn před `x`",
"videoinfo_watch_on_youTube": "Sledovat na YouTube",
"videoinfo_youTube_embed_link": "Vložení",
"crash_page_read_the_faq": "si přečetli <a href=\"`x`\">často kladené otázky (FAQ)</a>",
"crash_page_before_reporting": "Před nahlášením chyby se ujistěte, že jste:",
"preferences_quality_option_hd720": "HD720",
"preferences_quality_option_dash": "DASH (adaptivní kvalita)",
"generic_views_count_0": "{{count}} zhlédnutí",
"generic_views_count_1": "{{count}} zhlédnutí",
"generic_views_count_2": "{{count}} zhlédnutí",
"generic_subscriptions_count_0": "{{count}} odběr",
"generic_subscriptions_count_1": "{{count}} odběry",
"generic_subscriptions_count_2": "{{count}} odběrů",
"preferences_quality_dash_option_4320p": "4320p",
"generic_videos_count_0": "{{count}} video",
"generic_videos_count_1": "{{count}} videa",
"generic_videos_count_2": "{{count}} videí",
"preferences_quality_option_small": "Nízká",
"preferences_quality_dash_option_2160p": "2160p",
"preferences_quality_dash_option_1080p": "1080p",
"preferences_quality_dash_option_720p": "720p",
"preferences_quality_dash_option_360p": "360p",
"preferences_quality_dash_option_144p": "144p",
"preferences_quality_option_medium": "Střední",
"preferences_quality_dash_option_1440p": "1440p",
"invidious": "Invidious",
"View more comments on Reddit": "Zobrazit více komentářů na Redditu",
"Invalid TFA code": "Nesprávný TFA kód",
"generic_playlists_count_0": "{{count}} playlist",
"generic_playlists_count_1": "{{count}} playlisty",
"generic_playlists_count_2": "{{count}} playlistů",
"generic_subscribers_count_0": "{{count}} odběratel",
"generic_subscribers_count_1": "{{count}} odběratelé",
"generic_subscribers_count_2": "{{count}} odběratelů",
"preferences_watch_history_label": "Povolit historii sledování: ",
"preferences_quality_dash_option_240p": "240p",
"preferences_region_label": "Země obsahu: ",
"subscriptions_unseen_notifs_count_0": "{{count}} nezobrazené oznámení",
"subscriptions_unseen_notifs_count_1": "{{count}} nezobrazená oznámení",
"subscriptions_unseen_notifs_count_2": "{{count}} nezobrazených oznámení",
"Show replies": "Zobrazit odpovědi",
"Quota exceeded, try again in a few hours": "Kvóta překročena, zkuste to znovu za pár hodin",
"Password cannot be longer than 55 characters": "Heslo nesmí být delší než 55 znaků",
"comments_view_x_replies_0": "Zobrazit {{count}} odpověď",
"comments_view_x_replies_1": "Zobrazit {{count}} odpovědi",
"comments_view_x_replies_2": "Zobrazit {{count}} odpovědí",
"comments_points_count_0": "{{count}} bod",
"comments_points_count_1": "{{count}} body",
"comments_points_count_2": "{{count}} bodů",
"German (auto-generated)": "Němčina (automaticky generováno)",
"Indonesian (auto-generated)": "Indonéština (automaticky generováno)",
"Interlingue": "Interlingue",
"Italian (auto-generated)": "Italština (automaticky generováno)",
"Japanese (auto-generated)": "Japonština (automaticky generováno)",
"Korean (auto-generated)": "Korejština (automaticky generováno)",
"Russian (auto-generated)": "Ruština (automaticky generováno)",
"generic_count_months_0": "{{count}} měsícem",
"generic_count_months_1": "{{count}} měsíci",
"generic_count_months_2": "{{count}} měsíci",
"generic_count_weeks_0": "{{count}} týdnem",
"generic_count_weeks_1": "{{count}} týdny",
"generic_count_weeks_2": "{{count}} týdny",
"generic_count_minutes_0": "{{count}} minutou",
"generic_count_minutes_1": "{{count}} minutami",
"generic_count_minutes_2": "{{count}} minutami",
"footer_documentation": "Dokumentace",
"next_steps_error_message_refresh": "Obnovit stránku",
"Chinese": "Čínština",
"Dutch (auto-generated)": "Nizozemština (automaticky generováno)",
"Erroneous token": "Chybný token",
"tokens_count_0": "{{count}} token",
"tokens_count_1": "{{count}} tokeny",
"tokens_count_2": "{{count}} tokenů",
"Portuguese (Brazil)": "Portugalština (Brazílie)",
"Token is expired, please try again": "Token vypršel, zkuste to prosím znovu",
"English (United States)": "Angličtina (Spojené státy)",
"Cantonese (Hong Kong)": "Kantonština (Hong Kong)",
"French (auto-generated)": "Francouzština (automaticky generováno)",
"Turkish (auto-generated)": "Turečtina (automaticky generováno)",
"Vietnamese (auto-generated)": "Vietnamština (automaticky generováno)",
"Current version: ": "Aktuální verze: ",
"next_steps_error_message": "Měli byste zkusit: ",
"footer_donate_page": "Přispět",
"download_subtitles": "Titulky - `x` (.vtt)",
"%A %B %-d, %Y": "%A %B %-d, %Y",
"YouTube comment permalink": "Permanentní odkaz YouTube komentáře",
"permalink": "permalink",
"footer_original_source_code": "Původní zdrojový kód",
"adminprefs_modified_source_code_url_label": "URL repozitáře s upraveným zdrojovým kódem",
"Video unavailable": "Video není dostupné",
"next_steps_error_message_go_to_youtube": "Jít na YouTube",
"footer_modfied_source_code": "Upravený zdrojový kód",
"none": "žádné",
"videoinfo_invidious_embed_link": "Odkaz na vložení",
"user_saved_playlists": "`x` uložených playlistů",
"crash_page_you_found_a_bug": "Vypadá to, že jste našli chybu v Invidious!",
"user_created_playlists": "`x` vytvořených playlistů",
"crash_page_search_issue": "vyhledali <a href=\"`x`\">existující problémy na GitHubu</a>",
"crash_page_report_issue": "Pokud nepomohlo nic z výše uvedeného, <a href=\"`x`\">otevřete prosím nový problém na GitHubu</a> (pokud možno v angličtině) a zahrňte do zprávy následující text (NEpřekládejte jej):",
"preferences_quality_dash_label": "Preferovaná kvalita videí DASH: ",
"preferences_quality_dash_option_auto": "Automatická",
"preferences_quality_dash_option_best": "Nejlepší",
"preferences_quality_dash_option_worst": "Nejhorší",
"preferences_quality_dash_option_480p": "480p",
"Top enabled: ": "Povoleny nejlepší: ",
"generic_count_seconds_0": "{{count}} sekundou",
"generic_count_seconds_1": "{{count}} sekundami",
"generic_count_seconds_2": "{{count}} sekundami",
"preferences_save_player_pos_label": "Uložit pozici přehrávání: ",
"Incorrect password": "Nesprávné heslo",
"View as playlist": "Zobrazit jako playlist",
"View Reddit comments": "Zobrazit komentáře z Redditu",
"No such user": "Uživatel nenalezen",
"Playlist privacy": "Soukromí playlistu",
"Wrong answer": "Špatná odpověď",
"Could not pull trending pages.": "Nepodařilo se získat trendy stránky.",
"Erroneous CAPTCHA": "Chybná CAPTCHA",
"Password is a required field": "Heslo je vyžadované pole",
"preferences_automatic_instance_redirect_label": "Automatické přesměrování instance (fallback na redirect.invidious.io): ",
"Switch Invidious Instance": "Přepnout instanci Invidious",
"Empty playlist": "Prázdný playlist",
"footer_source_code": "Zdrojový kód",
"View YouTube comments": "Zobrazit YouTube komentáře",
"Blacklisted regions: ": "Oblasti na černé listině: ",
"Wrong username or password": "Nesprávné uživatelské jméno nebo heslo",
"Please sign in using 'Log in with Google'": "Přihlaste se prosím pomocí Googlu",
"Password cannot be empty": "Heslo nemůže být prázné",
"preferences_category_misc": "Různá nastavení",
"preferences_show_nick_label": "Zobrazit přezdívku na vrchu: ",
"Whitelisted regions: ": "Oblasti na bílé listině: ",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Zdravíme! Zdá se, že máte vypnutý JavaScript. Klikněte sem pro zobrazení komentářů - nezapomeňte, že se mohou načítat trochu déle.",
"User ID is a required field": "ID uživatele je vyžadované pole",
"Please log in": "Přihlaste se prosím",
"Invidious Private Feed for `x`": "Soukromý kanál Invidious pro `x`",
"Deleted or invalid channel": "Smazaný nebo neplatný kanál",
"This channel does not exist.": "Tento kanál neexistuje.",
"Hidden field \"token\" is a required field": "Skryté pole \"token\" je vyžadované",
"Wilson score: ": "Skóre Wilson: ",
"Shared `x`": "Zveřejněno `x`",
"Premieres in `x`": "Premiéra za `x`",
"View `x` comments": {
"([^.,0-9]|^)1([^.,0-9]|$)": "Zobrazit `x` komentář",
"": "Zobrazit `x` komentářů"
},
"Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "Nepodařilo se přihlásit, ujistěte se, že je povoleno dvoufázové ověřování (autentifikátor nebo SMS).",
"Login failed. This may be because two-factor authentication is not turned on for your account.": "Přihlášení selhalo. Toto se může stát, když není na vašem účtu povolené dvoufázové ověřování.",
"Could not get channel info.": "Nepodařilo se získat informace o kanálu.",
"Could not fetch comments": "Nepodařilo se získat komentáře",
"Could not create mix.": "Nepodařilo se vytvořit mix.",
"Hidden field \"challenge\" is a required field": "Skryté pole \"challenge\" je vyžadované",
"Released under the AGPLv3 on Github.": "Vydáno pod licencí AGPLv3 na GitHubu.",
"Hide replies": "Skrýt odpovědi",
"channel:`x`": "kanál: `x`",
"Load more": "Načíst další",
"Not a playlist.": "Není playlist.",
"Playlist does not exist.": "Playlist neexistuje.",
"Erroneous challenge": "Chybná výzva",
"Premieres `x`": "Premiéra `x`",
"CAPTCHA is a required field": "CAPTCHA je vyžadované pole",
"`x` ago": "Před `x`",
"search_message_change_filters_or_query": "Zkuste rozšířit vyhledávaný dotaz a/nebo změnit filtry.",
"search_filters_date_option_none": "Jakékoli datum",
"search_filters_date_label": "Datum nahrání",
"search_filters_type_option_all": "Jakýkoli typ",
"search_filters_duration_option_none": "Jakákoli délka",
"search_filters_type_label": "Typ",
"search_filters_duration_option_short": "Krátká (< 4 minuty)",
"search_message_no_results": "Nenalezeny žádné výsledky.",
"search_filters_title": "Filtry",
"search_filters_duration_option_medium": "Střední (4 - 20 minut)",
"search_filters_duration_option_long": "Dlouhá (> 20 minut)",
"search_message_use_another_instance": " Můžete také <a href=\"`x`\">hledat na jiné instanci</a>.",
"search_filters_features_label": "Vlastnosti",
"search_filters_features_option_three_sixty": "360°",
"search_filters_features_option_vr180": "VR180",
"search_filters_features_option_purchased": "Zakoupeno",
"search_filters_sort_label": "Řadit dle",
"search_filters_sort_option_relevance": "Relevantnost",
"search_filters_apply_button": "Použít vybrané filtry",
"Popular enabled: ": "Populární povoleno: "
}

View File

@ -1,464 +0,0 @@
{
"LIVE": "LIVE",
"Shared `x` ago": "Delt for `x` siden",
"Unsubscribe": "Opsig abonnement",
"Subscribe": "Abonner",
"View channel on YouTube": "Vis kanal på YouTube",
"View playlist on YouTube": "Vis afspilningsliste på YouTube",
"newest": "nyeste",
"oldest": "ældste",
"popular": "populært",
"last": "sidste",
"Next page": "Næste side",
"Previous page": "Forrige side",
"Clear watch history?": "Ryd afspilningshistorik?",
"New password": "Nyt kodeord",
"New passwords must match": "Nye kodeord skal matche",
"Cannot change password for Google accounts": "Kan ikke skifte kodeord til Google-konti",
"Authorize token?": "Godkend token?",
"Authorize token for `x`?": "Godkend token til `x`?",
"Yes": "Ja",
"No": "Nej",
"Import and Export Data": "Importer og Eksporter Data",
"Import": "Importer",
"Import Invidious data": "Importer Invidious JSON-data",
"Import YouTube subscriptions": "Importer YouTube/OPML-abonnementer",
"Import FreeTube subscriptions (.db)": "Importer FreeTube abonnementer (.db)",
"Import NewPipe subscriptions (.json)": "Importer NewPipe abonnementer (.json)",
"Import NewPipe data (.zip)": "Importer NewPipe data (.zip)",
"Export": "Exporter",
"Export subscriptions as OPML": "Exporter abonnementer som OPML",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Exporter abonnementer som OPML (til NewPipe & FreeTube)",
"Export data as JSON": "Eksporter Invidious-data som JSON",
"Delete account?": "Slet konto?",
"History": "Historik",
"An alternative front-end to YouTube": "Et alternativt front-end til YouTube",
"JavaScript license information": "JavaScript licens information",
"source": "kilde",
"Log in": "Log på",
"Log in/register": "Log på/registrer",
"Log in with Google": "Log på med Google",
"User ID": "Bruger ID",
"Password": "Kodeord",
"Time (h:mm:ss):": "Tid (t:mm:ss):",
"Text CAPTCHA": "Tekst CAPTCHA",
"Image CAPTCHA": "Billede CAPTCHA",
"Sign In": "Log ind",
"Register": "Registrer",
"E-mail": "E-mail",
"Google verification code": "Google-verifikationskode",
"Preferences": "Præferencer",
"preferences_category_player": "Afspillerindstillinger",
"preferences_video_loop_label": "Altid gentag: ",
"preferences_autoplay_label": "Auto afspil: ",
"preferences_continue_label": "Afspil næste som standard: ",
"preferences_continue_autoplay_label": "Auto afspil næste video: ",
"preferences_listen_label": "Lyt som standard: ",
"preferences_local_label": "Proxy videoer: ",
"preferences_speed_label": "Standard hastighed: ",
"preferences_quality_label": "Foretrukken video kvalitet: ",
"preferences_volume_label": "Lydstyrke: ",
"preferences_comments_label": "Standard kommentarer: ",
"youtube": "YouTube",
"reddit": "Reddit",
"preferences_captions_label": "Standard undertekster: ",
"Fallback captions: ": "Alternative undertekster: ",
"preferences_related_videos_label": "Vis relaterede videoer: ",
"preferences_annotations_label": "Vis annotationer som standard: ",
"preferences_extend_desc_label": "Automatisk udvid videoens beskrivelse: ",
"preferences_vr_mode_label": "Interaktive 360 graders videoer (kræver WebGL): ",
"preferences_category_visual": "Visuelle præferencer",
"preferences_player_style_label": "Afspiller stil: ",
"Dark mode: ": "Mørk tilstand: ",
"preferences_dark_mode_label": "Tema: ",
"dark": "mørk",
"light": "lys",
"preferences_thin_mode_label": "Tynd tilstand: ",
"preferences_category_subscription": "Abonnements præferencer",
"preferences_annotations_subscribed_label": "Vis annotationer som standard for abonnerede kanaler: ",
"Redirect homepage to feed: ": "Omdiriger startside til feed: ",
"preferences_max_results_label": "Antal videoer vist i feed: ",
"preferences_sort_label": "Sorter videoer efter: ",
"published": "offentliggjort",
"published - reverse": "offentliggjort - omvendt",
"alphabetically": "alfabetisk",
"alphabetically - reverse": "alfabetisk - omvendt",
"channel name": "kanalnavn",
"channel name - reverse": "kanalnavn - omvendt",
"Only show latest video from channel: ": "Vis kun seneste video fra kanal: ",
"Only show latest unwatched video from channel: ": "Vis kun seneste usete video fra kanal: ",
"preferences_unseen_only_label": "Vis kun usete: ",
"preferences_notifications_only_label": "Vis kun notifikationer (hvis der er nogle): ",
"Enable web notifications": "Aktiver webnotifikationer",
"`x` uploaded a video": "`x` uploadede en video",
"`x` is live": "`x` er live",
"preferences_category_data": "Data præferencer",
"Clear watch history": "Ryd afspilningshistorik",
"Import/export data": "Importer/exporter data",
"Change password": "Skift adgangskode",
"Manage subscriptions": "Administrer abonnementer",
"Manage tokens": "Administrer tokens",
"Watch history": "Afspilningshistorik",
"Delete account": "Slet konto",
"preferences_category_admin": "Administrator præferencer",
"preferences_default_home_label": "Standard startside: ",
"preferences_feed_menu_label": "Feed menu: ",
"Top enabled: ": "Top aktiveret: ",
"CAPTCHA enabled: ": "CAPTCHA aktiveret: ",
"Login enabled: ": "Login aktiveret: ",
"Registration enabled: ": "Registrering aktiveret: ",
"Report statistics: ": "Indsend statistik: ",
"Save preferences": "Gem præferencer",
"Subscription manager": "Abonnementsmanager",
"Token manager": "Tokenmanager",
"Token": "Token",
"Import/export": "Importer/eksporter",
"unsubscribe": "opsig abonnement",
"revoke": "tilbagekald",
"Subscriptions": "Abonnementer",
"search": "søg",
"Log out": "Log ud",
"Source available here.": "Kilde tilgængelig her.",
"View JavaScript license information.": "Vis JavaScriptlicensinformation.",
"View privacy policy.": "Vis privatpolitik.",
"Trending": "Trending",
"Public": "Offentlig",
"Unlisted": "Skjult",
"Private": "Privat",
"View all playlists": "Vis alle afspilningslister",
"Updated `x` ago": "Opdateret for `x` siden",
"Delete playlist `x`?": "Fjern spilleliste `x`?",
"Delete playlist": "Slet afspilningsliste",
"Create playlist": "Opret afspilningsliste",
"Title": "Titel",
"Playlist privacy": "Privatlivsindstillinger for afspilningsliste",
"Editing playlist `x`": "Redigerer afspilningsliste `x`",
"Show more": "Vis mere",
"Show less": "Vis mindre",
"Watch on YouTube": "Se på YouTube",
"Hide annotations": "Skjul annotationer",
"Show annotations": "Vis annotationer",
"Genre: ": "Genre: ",
"License: ": "Licens: ",
"Family friendly? ": "Familievenlig? ",
"Wilson score: ": "Wilson score: ",
"Engagement: ": "Engagement: ",
"Whitelisted regions: ": "Whitelistede regioner: ",
"Blacklisted regions: ": "Blacklistede regioner: ",
"Shared `x`": "Delt `x`",
"Premieres in `x`": "Har premiere om `x`",
"Premieres `x`": "Har premiere om `x`",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Hej! Det ser ud til at du har JavaScript slået fra. Klik her for at se kommentarer, vær opmærksom på at de kan tage længere om at indlæse.",
"View YouTube comments": "Vis YouTube kommentarer",
"View more comments on Reddit": "Se flere kommentarer på Reddit",
"View `x` comments": {
"([^.,0-9]|^)1([^.,0-9]|$)": "Vis `x` kommentarer.([^.,0-9]|^)1([^.,0-9]|$)",
"": "Vis `x` kommentarer"
},
"View Reddit comments": "Vis Reddit kommentarer",
"Hide replies": "Skjul svar",
"Show replies": "Vis svar",
"Incorrect password": "Forkert adgangskode",
"Quota exceeded, try again in a few hours": "Kvota overskredet, prøv igen om et par timer",
"Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "Login fejlet, tjek at totrinsbekræftelse (Authenticator eller SMS) er slået til.",
"Invalid TFA code": "Ugyldig TFA kode",
"Login failed. This may be because two-factor authentication is not turned on for your account.": "Login fejlede. Dette kan skyldes, at to-faktor autentificering ikke er aktiveret for din konto.",
"Wrong answer": "Forkert svar",
"Erroneous CAPTCHA": "Fejlagtig CAPTCHA",
"CAPTCHA is a required field": "CAPTCHA er et obligatorisk felt",
"User ID is a required field": "Bruger ID er et krævet felt",
"Password is a required field": "Adgangskode er et obligatorisk felt",
"Wrong username or password": "Forkert brugernavn eller adgangskode",
"Please sign in using 'Log in with Google'": "Log ind via 'Log ind med Google'",
"Password cannot be empty": "Adgangskoden må ikke være tom",
"Password cannot be longer than 55 characters": "Adgangskoden må ikke være længere end 55 tegn",
"Please log in": "Venligst log ind",
"channel:`x`": "kanal: 'x'",
"Deleted or invalid channel": "Slettet eller invalid kanal",
"This channel does not exist.": "Denne kanal eksisterer ikke.",
"Could not get channel info.": "Kunne ikke hente kanal info.",
"Could not fetch comments": "Kunne ikke hente kommentarer",
"`x` ago": "'x' siden",
"Load more": "Hent flere",
"Could not create mix.": "Kunne ikke skabe blanding.",
"Empty playlist": "Tom playliste",
"Not a playlist.": "Ikke en playliste.",
"Playlist does not exist.": "Playlist eksisterer ikke.",
"Esperanto": "Esperanto",
"Czech": "Tjekkisk",
"Danish": "Dansk",
"Community": "Samfund",
"Afrikaans": "Afrikansk",
"Portuguese": "Portugisisk",
"Ukrainian": "Ukrainsk",
"Fallback comments: ": "Fallback kommentarer: ",
"Popular": "Populær",
"footer_donate_page": "Doner",
"Gujarati": "Gujarati",
"Punjabi": "Punjabi",
"Sundanese": "Sundanesisk",
"Urdu": "Urdu",
"preferences_region_label": "Indhold land: ",
"Hidden field \"challenge\" is a required field": "Det skjulte felt \"challenge\" er et påkrævet felt",
"Albanian": "Albansk",
"preferences_quality_dash_label": "Fortrukket DASH video kvalitet: ",
"search_filters_features_option_live": "Direkte",
"Lao": "Lao-tse",
"Filipino": "Filippinsk",
"Greek": "Græsk",
"Kurdish": "Kurdisk",
"Malay": "Malaysisk",
"Romanian": "Rumænsk",
"Somali": "Somalisk",
"preferences_locale_label": "Sprog: ",
"News": "Nyheder",
"permalink": "permalink",
"search_filters_sort_option_date": "Upload dato",
"search_filters_features_label": "Funktioner",
"Khmer": "Khmer",
"Finnish": "Finsk",
"search_filters_date_option_week": "Denne uge",
"Korean": "Koreansk",
"Telugu": "Telugu",
"Malayalam": "Malayalam",
"View as playlist": "Se som spilleliste",
"Hungarian": "Ungarsk",
"Welsh": "Walisisk",
"search_filters_features_option_subtitles": "Undertekster/CC",
"Bosnian": "Bosnisk",
"Yiddish": "Jiddisch",
"Belarusian": "Belarussisk",
"search_filters_date_option_today": "I dag",
"Shona": "Shona",
"Slovenian": "Slovensk",
"Gaming": "Gaming",
"Bangla": "Bengali",
"Swahili": "Swahili",
"`x` marked it with a ❤": "`x`markeret med et ❤",
"Kyrgyz": "Kirgisisk",
"Turkish": "Tyrkisk",
"adminprefs_modified_source_code_url_label": "URL-adresse til modificeret kildekodelager",
"Switch Invidious Instance": "Skift Invidious instans",
"Samoan": "Samoansk",
"Spanish": "Spansk",
"%A %B %-d, %Y": "%A %B %-d, %Y",
"footer_documentation": "Dokumentation",
"Pashto": "Pashto",
"footer_modfied_source_code": "Modificeret Kildekode",
"Released under the AGPLv3 on Github.": "Udgivet under AGPLv3 på GitHub.",
"Tajik": "Tadsjikisk",
"search_filters_date_option_month": "Denne måned",
"Hebrew": "Hebraisk",
"Kannada": "Kannada",
"Current version: ": "Nuværende version: ",
"Amharic": "Amharisk",
"Swedish": "Svensk",
"Corsican": "Korsikansk",
"search_filters_type_option_movie": "Film",
"Could not pull trending pages.": "Kunne ikke hente trending sider.",
"English": "Engelsk",
"search_filters_features_option_hd": "HD",
"Hausa": "Islandsk",
"search_filters_date_option_year": "Dette år",
"Japanese": "Japansk",
"search_filters_type_label": "Type",
"Icelandic": "Islandsk",
"Basque": "Baskisk",
"search_filters_sort_option_rating": "Bedømmelse",
"Yoruba": "Yoruba",
"Erroneous token": "Fejlagtig token",
"Videos": "Videoer",
"search_filters_type_option_show": "Vis",
"Luxembourgish": "Luxemboursk",
"Vietnamese": "Vietnamesisk",
"Latvian": "Lettisk",
"Indonesian": "Indonesisk",
"search_filters_duration_label": "Varighed",
"footer_original_source_code": "Original kildekode",
"Search": "Søg",
"Serbian": "Serbisk",
"Armenian": "Armensk",
"Bulgarian": "Bulgarsk",
"French": "Fransk",
"Burmese": "Burmesisk",
"Macedonian": "Makedonsk",
"Southern Sotho": "Sydlige Sotho",
"About": "Omkring",
"Malagasy": "Madagaskiske",
"Rating: ": "Bedømmelse: ",
"Movies": "Film",
"YouTube comment permalink": "Youtube kommentarer permalink",
"search_filters_features_option_location": "Lokation",
"search_filters_features_option_hdr": "HDR",
"Cebuano": "Cebuano (Sugbuanon)",
"Nyanja": "Nyanja",
"Chinese (Simplified)": "Kinesisk (forenklet)",
"Chinese (Traditional)": "Kinesisk (traditionelt)",
"Dutch": "Hollandsk",
"Estonian": "Estisk",
"preferences_automatic_instance_redirect_label": "Automatisk eksempel omdirigering (Fallback til redirect.invidious.io): ",
"Nepali": "Nepalesisk",
"Norwegian Bokmål": "Norsk Bokmål",
"(edited)": "(ændret)",
"preferences_show_nick_label": "Vis kælenavn på toppen: ",
"Galician": "Galisisk",
"German": "Tysk",
"Maori": "Maori",
"Slovak": "Slovakisk",
"search_filters_sort_option_relevance": "Relevans",
"search_filters_date_option_hour": "Sidste time",
"search_filters_type_option_playlist": "Spilleliste",
"search_filters_duration_option_long": "Lang (> 20 minutter)",
"search_filters_features_option_c_commons": "Creative Commons",
"Marathi": "Marathi",
"Sindhi": "Sindhi",
"preferences_category_misc": "Diverse indstillinger",
"Erroneous challenge": "Fejlagtig udfordring",
"Hindi": "Hindi",
"Igbo": "Igbo",
"Javanese": "Javanesisk",
"Kazakh": "Kasabhisk",
"Latin": "Latinsk",
"Lithuanian": "Lituaisk",
"Mongolian": "Mongolsk",
"Spanish (Latin America)": "Spansk (Latinamerika)",
"Uzbek": "Usbekisk",
"Western Frisian": "Vestfrisisk",
"Top": "Top",
"Music": "Musik",
"search_filters_sort_option_views": "Antal visninger",
"search_filters_sort_label": "Sorter efter",
"Zulu": "Zulu",
"Invidious Private Feed for `x`": "Invidious Privat Feed til `x`",
"English (auto-generated)": "Engelsk (autogenereret)",
"Arabic": "Arabisk",
"Croatian": "Kroatisk",
"Hawaiian": "Hawaiiansk",
"Maltese": "Maltesisk",
"Polish": "Polsk",
"Russian": "Russisk",
"Download": "Hent",
"Download as: ": "Hent som: ",
"Playlists": "Spillelister",
"next_steps_error_message_refresh": "Opdater",
"next_steps_error_message_go_to_youtube": "Gå til Youtube",
"footer_source_code": "Kildekode",
"Tamil": "Tamil",
"Xhosa": "Xhosa",
"next_steps_error_message": "Efter det burde du prøve at: ",
"Sinhala": "Singalesisk (Sinhala)",
"Thai": "Thai",
"No such user": "Brugeren findes ikke",
"Token is expired, please try again": "Token er udløbet, prøv igen",
"Catalan": "Catalansk",
"Haitian Creole": "Haitiansk",
"Irish": "Irsk",
"Persian": "Persisk",
"Scottish Gaelic": "Skotsk Gælisk",
"Default": "Standard",
"Video mode": "Videotilstand",
"search_filters_duration_option_short": "Kort (< 4 minutter)",
"Hidden field \"token\" is a required field": "Det skjulte felt \"token\" er et påkrævet felt",
"Azerbaijani": "Aserbajdsjansk",
"Georgian": "Georgisk",
"Italian": "Italiensk",
"Audio mode": "Lydtilstand",
"search_filters_type_option_video": "Video",
"search_filters_type_option_channel": "Kanal",
"search_filters_features_option_three_d": "3D",
"search_filters_features_option_four_k": "4K",
"Hmong": "Hmong",
"preferences_quality_option_medium": "Medium",
"preferences_quality_option_small": "Lille",
"preferences_quality_dash_option_best": "Bedste",
"preferences_quality_dash_option_worst": "Værste",
"preferences_quality_dash_option_4320p": "4320p",
"preferences_quality_dash_option_1080p": "1080p",
"preferences_quality_dash_option_720p": "720p",
"preferences_quality_dash_option_480p": "480p",
"preferences_quality_dash_option_360p": "360p",
"preferences_quality_dash_option_144p": "144p",
"invidious": "Invidious",
"search_filters_features_option_purchased": "Købt",
"search_filters_features_option_three_sixty": "360°",
"none": "ingen",
"videoinfo_started_streaming_x_ago": "Streamen blev startet for `x`siden",
"videoinfo_watch_on_youTube": "Se på YouTube",
"videoinfo_youTube_embed_link": "Integrer",
"videoinfo_invidious_embed_link": "Integrer Link",
"download_subtitles": "Undertekster - `x`(.vtt)",
"user_created_playlists": "`x`opretede spillelister",
"user_saved_playlists": "´x`gemte spillelister",
"Video unavailable": "Video ikke tilgængelig",
"preferences_save_player_pos_label": "Gem afspilningsposition: ",
"preferences_quality_dash_option_auto": "Auto",
"preferences_quality_option_hd720": "HD720",
"preferences_quality_dash_option_2160p": "2160p",
"preferences_quality_option_dash": "DASH (adaptiv kvalitet)",
"preferences_quality_dash_option_1440p": "1440p",
"preferences_quality_dash_option_240p": "240p",
"subscriptions_unseen_notifs_count": "{{count}} uset notifikation",
"subscriptions_unseen_notifs_count_plural": "{{count}} usete notifikationer",
"comments_view_x_replies": "Vis {{count}} svar",
"comments_view_x_replies_plural": "Vis {{count}} svar",
"comments_points_count": "{{count}} point",
"comments_points_count_plural": "{{count}} point",
"generic_count_years": "{{count}} år",
"generic_count_years_plural": "{{count}} år",
"generic_count_months": "{{count}} måned",
"generic_count_months_plural": "{{count}} måneder",
"generic_count_days": "{{count}} dag",
"generic_count_days_plural": "{{count}} dage",
"generic_count_minutes": "{{count}} minut",
"generic_count_minutes_plural": "{{count}} minutter",
"generic_count_seconds": "{{count}} sekund",
"generic_count_seconds_plural": "{{count}} sekunder",
"generic_subscribers_count": "{{count}} abonnent",
"generic_subscribers_count_plural": "{{count}} abonnenter",
"generic_subscriptions_count": "{{count}} abonnement",
"generic_subscriptions_count_plural": "{{count}} abonnementer",
"generic_videos_count": "{{count}} video",
"generic_videos_count_plural": "{{count}} videoer",
"English (United States)": "Engelsk (USA)",
"French (auto-generated)": "Fransk (autogenereret)",
"Spanish (auto-generated)": "Spansk (autogenereret)",
"crash_page_before_reporting": "Før du rapporterer en fejl, skal du sikre dig, at du har:",
"crash_page_refresh": "forsøgte at <a href=\"`x`\">opdatere siden</a>",
"generic_playlists_count": "{{count}} spilleliste",
"generic_playlists_count_plural": "{{count}} spillelister",
"preferences_watch_history_label": "Aktiver afspilningshistorik: ",
"tokens_count": "{{count}} token",
"tokens_count_plural": "{{count}} tokens",
"Cantonese (Hong Kong)": "Kantonesisk (Hongkong)",
"Chinese": "Kinesisk",
"Chinese (China)": "Kinesisk (Kina)",
"Chinese (Hong Kong)": "Kinesisk (Hongkong)",
"Chinese (Taiwan)": "Kinesisk (Taiwan)",
"Dutch (auto-generated)": "Hollandsk (autogenereret)",
"Indonesian (auto-generated)": "Indonesisk (autogenereret)",
"Interlingue": "Interlingue",
"Japanese (auto-generated)": "Japansk (autogenereret)",
"Korean (auto-generated)": "Koreansk (autogenereret)",
"Russian (auto-generated)": "Russisk (autogenereret)",
"Turkish (auto-generated)": "Tyrkisk (autogenereret)",
"Vietnamese (auto-generated)": "Vietnamesisk (autogenereret)",
"crash_page_report_issue": "Hvis intet af ovenstående hjalp, bedes du <a href=\"`x`\">åbne et nyt problem på GitHub</a> (helst på engelsk) og inkludere følgende tekst i din besked (oversæt IKKE denne tekst):",
"English (United Kingdom)": "Engelsk (Storbritannien)",
"Italian (auto-generated)": "Italiensk (autogenereret)",
"Portuguese (auto-generated)": "Portugisisk (autogenereret)",
"Portuguese (Brazil)": "Portugisisk (Brasilien)",
"generic_views_count": "{{count}} visning",
"generic_views_count_plural": "{{count}} visninger",
"generic_count_hours": "{{count}} time",
"generic_count_hours_plural": "{{count}} timer",
"Spanish (Spain)": "Spansk (Spanien)",
"crash_page_switch_instance": "forsøgte at <a href=\"`x`\">bruge en anden instans</a>",
"German (auto-generated)": "Tysk (autogenereret)",
"Spanish (Mexico)": "Spansk (Mexico)",
"generic_count_weeks": "{{count}} uge",
"generic_count_weeks_plural": "{{count}} uger",
"crash_page_you_found_a_bug": "Det ser ud til, at du har fundet en fejl i Invidious!",
"crash_page_read_the_faq": "læs <a href=\"`x`\">Ofte stillede spørgsmål (FAQ)</a>",
"crash_page_search_issue": "søgte efter <a href=\"`x`\">eksisterende problemer på GitHub</a>",
"search_filters_title": "Filter"
}

View File

@ -1,19 +1,22 @@
{
"`x` subscribers": "`x` Abonnenten",
"`x` videos": "`x` Videos",
"`x` playlists": "`x` Wiedergabelisten",
"LIVE": "LIVE",
"Shared `x` ago": "Vor `x` geteilt",
"Unsubscribe": "Abo beenden",
"Unsubscribe": "Abbestellen",
"Subscribe": "Abonnieren",
"View channel on YouTube": "Kanal auf YouTube anzeigen",
"View playlist on YouTube": "Wiedergabeliste auf YouTube anzeigen",
"newest": "neueste",
"oldest": "älteste",
"popular": "beliebteste",
"last": "neueste",
"popular": "beliebt",
"last": "letzte",
"Next page": "Nächste Seite",
"Previous page": "Vorherige Seite",
"Clear watch history?": "Verlauf löschen?",
"New password": "Neues Passwort",
"New passwords must match": "Neue Passwörter müssen übereinstimmen",
"New passwords must match": "Neue Passwörter müssen gleich sein",
"Cannot change password for Google accounts": "Ich kann das Passwort deines Google Kontos nicht ändern",
"Authorize token?": "Token autorisieren?",
"Authorize token for `x`?": "Token für `x` autorisieren?",
@ -21,24 +24,24 @@
"No": "Nein",
"Import and Export Data": "Daten importieren und exportieren",
"Import": "Importieren",
"Import Invidious data": "Invidious-JSON-Daten importieren",
"Import YouTube subscriptions": "YouTube-/OPML-Abonnements importieren",
"Import Invidious data": "Invidious Daten importieren",
"Import YouTube subscriptions": "YouTube Abonnements importieren",
"Import FreeTube subscriptions (.db)": "FreeTube Abonnements importieren (.db)",
"Import NewPipe subscriptions (.json)": "NewPipe Abonnements importieren (.json)",
"Import NewPipe data (.zip)": "NewPipe Daten importieren (.zip)",
"Export": "Exportieren",
"Export subscriptions as OPML": "Abonnements als OPML exportieren",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Abonnements als OPML exportieren (für NewPipe & FreeTube)",
"Export data as JSON": "Invidious-Daten als JSON exportieren",
"Delete account?": "Konto löschen?",
"Export data as JSON": "Daten als JSON exportieren",
"Delete account?": "Account löschen?",
"History": "Verlauf",
"An alternative front-end to YouTube": "Eine alternative Oberfläche für YouTube",
"JavaScript license information": "JavaScript Lizenzinformationen",
"source": "Quelle",
"Log in": "Anmelden",
"Log in/register": "Anmelden/registrieren",
"Log in with Google": "Mit Google anmelden",
"User ID": "Benutzer-ID",
"Log in": "Einloggen",
"Log in/register": "Einloggen/Registrieren",
"Log in with Google": "Mit Google einloggen",
"User ID": "Benutzer ID",
"Password": "Passwort",
"Time (h:mm:ss):": "Zeit (h:mm:ss):",
"Text CAPTCHA": "Text CAPTCHA",
@ -48,39 +51,35 @@
"E-mail": "E-Mail",
"Google verification code": "Google-Bestätigungscode",
"Preferences": "Einstellungen",
"preferences_category_player": "Wiedergabeeinstellungen",
"preferences_video_loop_label": "Immer wiederholen: ",
"preferences_autoplay_label": "Automatisch abspielen: ",
"preferences_continue_label": "Immer automatisch nächstes Video abspielen: ",
"preferences_continue_autoplay_label": "Nächstes Video automatisch abspielen: ",
"preferences_listen_label": "Nur Ton als Standard: ",
"preferences_local_label": "Videos durch Proxy leiten: ",
"preferences_speed_label": "Standardgeschwindigkeit: ",
"preferences_quality_label": "Bevorzugte Videoqualität: ",
"preferences_volume_label": "Wiedergabelautstärke: ",
"preferences_comments_label": "Standardkommentare: ",
"youtube": "YouTube",
"reddit": "Reddit",
"preferences_captions_label": "Standarduntertitel: ",
"Player preferences": "Wiedergabeeinstellungen",
"Always loop: ": "Immer wiederholen: ",
"Autoplay: ": "Automatisch abspielen: ",
"Play next by default: ": "Immer automatisch nächstes Video spielen: ",
"Autoplay next video: ": "nächstes Video automatisch abspielen: ",
"Listen by default: ": "Nur Ton als Standard: ",
"Proxy videos: ": "Proxy-Videos: ",
"Default speed: ": "Standardgeschwindigkeit: ",
"Preferred video quality: ": "Bevorzugte Videoqualität: ",
"Player volume: ": "Wiedergabelautstärke: ",
"Default comments: ": "Standardkommentare: ",
"youtube": "youtube",
"reddit": "reddit",
"Default captions: ": "Standarduntertitel: ",
"Fallback captions: ": "Ersatzuntertitel: ",
"preferences_related_videos_label": "Ähnliche Videos anzeigen: ",
"preferences_annotations_label": "Anmerkungen standardmäßig anzeigen: ",
"preferences_extend_desc_label": "Videobeschreibung automatisch erweitern: ",
"preferences_vr_mode_label": "Interaktive 360-Grad-Videos (erfordert WebGL): ",
"preferences_category_visual": "Anzeigeeinstellungen",
"preferences_player_style_label": "Player-Stil: ",
"Show related videos: ": "Ähnliche Videos anzeigen? ",
"Show annotations by default: ": "Standardmäßig Anmerkungen anzeigen? ",
"Visual preferences": "Anzeigeeinstellungen",
"Player style: ": "Abspielgeräterstil: ",
"Dark mode: ": "Nachtmodus: ",
"preferences_dark_mode_label": "Modus: ",
"Theme: ": "Modus: ",
"dark": "Nachtmodus",
"light": "hell",
"preferences_thin_mode_label": "Schlanker Modus: ",
"preferences_category_misc": "Sonstige Einstellungen",
"preferences_automatic_instance_redirect_label": "Automatische Instanzweiterleitung (über redirect.invidious.io): ",
"preferences_category_subscription": "Abonnementeinstellungen",
"preferences_annotations_subscribed_label": "Anmerkungen für abonnierte Kanäle standardmäßig anzeigen? ",
"light": "klarer Modus",
"Thin mode: ": "Schlanker Modus: ",
"Subscription preferences": "Abonnementeinstellungen",
"Show annotations by default for subscribed channels: ": "Anmerkungen für abonnierte Kanäle standardmäßig anzeigen? ",
"Redirect homepage to feed: ": "Startseite zu Feed umleiten: ",
"preferences_max_results_label": "Anzahl von Videos die im Feed angezeigt werden: ",
"preferences_sort_label": "Videos sortieren nach: ",
"Number of videos shown in feed: ": "Anzahl von Videos die im Feed angezeigt werden: ",
"Sort videos by: ": "Videos sortieren nach: ",
"published": "veröffentlicht",
"published - reverse": "veröffentlicht - invertiert",
"alphabetically": "alphabetisch",
@ -89,43 +88,45 @@
"channel name - reverse": "Kanalname - invertiert",
"Only show latest video from channel: ": "Nur neueste Videos des Kanals anzeigen: ",
"Only show latest unwatched video from channel: ": "Nur neueste ungesehene Videos des Kanals anzeigen: ",
"preferences_unseen_only_label": "Nur ungesehene anzeigen: ",
"preferences_notifications_only_label": "Nur Benachrichtigungen anzeigen (wenn es welche gibt): ",
"Only show unwatched: ": "Nur ungesehene anzeigen: ",
"Only show notifications (if there are any): ": "Nur Benachrichtigungen anzeigen (wenn es welche gibt): ",
"Enable web notifications": "Webbenachrichtigungen aktivieren",
"`x` uploaded a video": "`x` hat ein Video hochgeladen",
"`x` is live": "`x` ist live",
"preferences_category_data": "Dateneinstellungen",
"Data preferences": "Dateneinstellungen",
"Clear watch history": "Verlauf löschen",
"Import/export data": "Daten importieren/exportieren",
"Import/export data": "Daten im-/exportieren",
"Change password": "Passwort ändern",
"Manage subscriptions": "Abonnements verwalten",
"Manage tokens": "Tokens verwalten",
"Watch history": "Verlauf",
"Delete account": "Account löschen",
"preferences_category_admin": "Administrator-Einstellungen",
"preferences_default_home_label": "Standard-Startseite: ",
"preferences_feed_menu_label": "Feed-Menü: ",
"preferences_show_nick_label": "Nutzernamen oben anzeigen: ",
"Administrator preferences": "Administrator-Einstellungen",
"Default homepage: ": "Standard-Startseite: ",
"Feed menu: ": "Feed-Menü: ",
"Top enabled: ": "Top aktiviert? ",
"CAPTCHA enabled: ": "CAPTCHA aktiviert? ",
"Login enabled: ": "Anmeldung aktiviert: ",
"Login enabled: ": "Login aktiviert? ",
"Registration enabled: ": "Registrierung aktiviert? ",
"Report statistics: ": "Statistiken berichten? ",
"Save preferences": "Einstellungen speichern",
"Subscription manager": "Abonnementverwaltung",
"Token manager": "Tokenverwalter",
"Token": "Token",
"`x` subscriptions": "`x` Abonnements",
"`x` tokens": "`x` Tokens",
"Import/export": "Importieren/Exportieren",
"unsubscribe": "abbestellen",
"revoke": "widerrufen",
"Subscriptions": "Abonnements",
"`x` unseen notifications": "`x` ungesehene Benachrichtigungen",
"search": "Suchen",
"Log out": "Abmelden",
"Released under the AGPLv3 on Github.": "Auf GitHub unter der AGPLv3 Lizenz veröffentlicht.",
"Released under the AGPLv3 by Omar Roth.": "Veröffentlicht unter AGPLv3 von Omar Roth.",
"Source available here.": "Quellcode verfügbar hier.",
"View JavaScript license information.": "Javascript Lizenzinformationen anzeigen.",
"View privacy policy.": "Datenschutzerklärung einsehen.",
"Trending": "Angesagt",
"Trending": "Trending",
"Public": "Öffentlich",
"Unlisted": "Nicht aufgeführt",
"Private": "Privat",
@ -137,10 +138,7 @@
"Title": "Titel",
"Playlist privacy": "Vertrauliche Wiedergabeliste",
"Editing playlist `x`": "Wiedergabeliste bearbeiten `x`",
"Show more": "Mehr anzeigen",
"Show less": "Weniger anzeigen",
"Watch on YouTube": "Video auf YouTube ansehen",
"Switch Invidious Instance": "Invidious Instanz wechseln",
"Hide annotations": "Anmerkungen ausblenden",
"Show annotations": "Anmerkungen anzeigen",
"Genre: ": "Genre: ",
@ -151,30 +149,28 @@
"Whitelisted regions: ": "Erlaubte Regionen: ",
"Blacklisted regions: ": "Unerlaubte Regionen: ",
"Shared `x`": "Geteilt `x`",
"`x` views": "`x` Aufrufe",
"Premieres in `x`": "Zuerst gesehen in `x`",
"Premieres `x`": "Erster Start `x`",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Hallo! Anscheinend haben Sie JavaScript deaktiviert. Klicken Sie hier um Kommentare anzuzeigen, beachten sie dass es etwas länger dauern kann um sie zu laden.",
"View YouTube comments": "YouTube Kommentare anzeigen",
"View more comments on Reddit": "Mehr Kommentare auf Reddit anzeigen",
"View `x` comments": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` Kommentare anzeigen",
"": "`x` Kommentare anzeigen"
},
"View `x` comments": "`x` Kommentare anzeigen",
"View Reddit comments": "Reddit Kommentare anzeigen",
"Hide replies": "Antworten verstecken",
"Show replies": "Antworten anzeigen",
"Incorrect password": "Falsches Passwort",
"Quota exceeded, try again in a few hours": "Kontingent überschritten, versuche es in ein paar Stunden erneut",
"Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "Anmeldung nicht möglich, stellen Sie sicher, dass die Zwei-Faktor-Authentisierung (Authenticator oder SMS) aktiviert ist.",
"Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "Login nicht möglich, stellen Sie sicher dass two-factor Authentifikation (Authentifizierung oder SMS) aktiviert ist.",
"Invalid TFA code": "Ungültiger TFA Code",
"Login failed. This may be because two-factor authentication is not turned on for your account.": "Die Anmeldung ist fehlgeschlagen. Dies kann daran liegen, dass die Zwei-Faktor-Authentisierung für Ihr Konto nicht aktiviert ist.",
"Login failed. This may be because two-factor authentication is not turned on for your account.": "Login fehlgeschlagen. Das kann daran liegen dass two-factor Authentifizierung in ihrem Account nicht aktiviert ist.",
"Wrong answer": "Ungültige Antwort",
"Erroneous CAPTCHA": "Ungültiges CAPTCHA",
"CAPTCHA is a required field": "CAPTCHA ist eine erforderliche Eingabe",
"User ID is a required field": "Benutzer ID ist eine erforderliche Eingabe",
"Password is a required field": "Passwort ist eine erforderliche Eingabe",
"Wrong username or password": "Ungültiger Benutzername oder Passwort",
"Please sign in using 'Log in with Google'": "Bitte melden Sie sich mit Mit Google anmelden an",
"Please sign in using 'Log in with Google'": "Bitte melden sie sich mit 'Mit Google anmelden' an",
"Password cannot be empty": "Passwort darf nicht leer sein",
"Password cannot be longer than 55 characters": "Passwort darf nicht länger als 55 Zeichen sein",
"Please log in": "Bitte anmelden",
@ -184,15 +180,17 @@
"This channel does not exist.": "Dieser Kanal existiert nicht.",
"Could not get channel info.": "Kanalinformationen konnten nicht geladen werden.",
"Could not fetch comments": "Kommentare konnten nicht geladen werden",
"View `x` replies": "Zeige `x` Antworten",
"`x` ago": "vor `x`",
"Load more": "Mehr laden",
"`x` points": "`x` Punkte",
"Could not create mix.": "Mix konnte nicht erstellt werden.",
"Empty playlist": "Wiedergabeliste ist leer",
"Not a playlist.": "Ungültige Wiedergabeliste.",
"Playlist does not exist.": "Wiedergabeliste existiert nicht.",
"Could not pull trending pages.": "Trendenz-Seiten konnten nicht geladen werden.",
"Hidden field \"challenge\" is a required field": "Verstecktes Feld challenge ist eine erforderliche Eingabe",
"Hidden field \"token\" is a required field": "Verstecktes Feld token ist eine erforderliche Eingabe",
"Empty playlist": "Playlist ist leer",
"Not a playlist.": "Ungültige Playlist.",
"Playlist does not exist.": "Playlist existiert nicht.",
"Could not pull trending pages.": "Trending Seiten konnten nicht geladen werden.",
"Hidden field \"challenge\" is a required field": "Verstecktes Feld \"challenge\" ist eine erforderliche Eingabe",
"Hidden field \"token\" is a required field": "Verstecktes Feld \"token\" ist eine erforderliche Eingabe",
"Erroneous challenge": "Ungültiger Test",
"Erroneous token": "Ungültiger Token",
"No such user": "Ungültiger Benutzer",
@ -303,13 +301,19 @@
"Yiddish": "Jiddisch",
"Yoruba": "Joruba",
"Zulu": "Zulu",
"`x` years": "`x` Jahre",
"`x` months": "`x` Monate",
"`x` weeks": "`x` Wochen",
"`x` days": "`x` Tage",
"`x` hours": "`x` Stunden",
"`x` minutes": "`x` Minuten",
"`x` seconds": "`x` Sekunden",
"Fallback comments: ": "Alternative Kommentare: ",
"Popular": "Populär",
"Search": "Suchen",
"Top": "Top",
"About": "Über",
"Rating: ": "Bewertung: ",
"preferences_locale_label": "Sprache: ",
"Language: ": "Sprache: ",
"View as playlist": "Als Wiedergabeliste anzeigen",
"Default": "Standard",
"Music": "Musik",
@ -318,7 +322,7 @@
"Movies": "Filme",
"Download": "Herunterladen",
"Download as: ": "Herunterladen als: ",
"%A %B %-d, %Y": "%A %-d %B %Y",
"%A %B %-d, %Y": "%A %B %-d, %Y",
"(edited)": "(editiert)",
"YouTube comment permalink": "YouTube-Kommentar Permalink",
"permalink": "Permalink",
@ -328,148 +332,5 @@
"Videos": "Videos",
"Playlists": "Wiedergabelisten",
"Community": "Gemeinschaft",
"search_filters_sort_option_relevance": "Relevanz",
"search_filters_sort_option_rating": "Bewertung",
"search_filters_sort_option_date": "Datum",
"search_filters_sort_option_views": "Aufrufe",
"search_filters_type_label": "Inhaltstyp",
"search_filters_duration_label": "Dauer",
"search_filters_features_label": "Eigenschaften",
"search_filters_sort_label": "sortieren",
"search_filters_date_option_hour": "Letzte Stunde",
"search_filters_date_option_today": "Heute",
"search_filters_date_option_week": "Diese Woche",
"search_filters_date_option_month": "Diesen Monat",
"search_filters_date_option_year": "Dieses Jahr",
"search_filters_type_option_video": "Video",
"search_filters_type_option_channel": "Kanal",
"search_filters_type_option_playlist": "Wiedergabeliste",
"search_filters_type_option_movie": "Film",
"search_filters_type_option_show": "Anzeigen",
"search_filters_features_option_hd": "HD",
"search_filters_features_option_subtitles": "Untertitel / CC",
"search_filters_features_option_c_commons": "Creative Commons",
"search_filters_features_option_three_d": "3D",
"search_filters_features_option_live": "Live",
"search_filters_features_option_four_k": "4K",
"search_filters_features_option_location": "Standort",
"search_filters_features_option_hdr": "HDR",
"Current version: ": "Aktuelle Version: ",
"next_steps_error_message": "Danach folgendes versuchen: ",
"next_steps_error_message_refresh": "Aktualisieren",
"next_steps_error_message_go_to_youtube": "Zu YouTube gehen",
"footer_donate_page": "Spende",
"search_filters_duration_option_long": "Lang (> 20 Minuten)",
"footer_original_source_code": "Original Quellcode",
"footer_modfied_source_code": "Modifizierter Quellcode",
"footer_documentation": "Dokumentation",
"footer_source_code": "Quellcode",
"adminprefs_modified_source_code_url_label": "URL zum Repositorie des modifizierten Quellcodes",
"search_filters_duration_option_short": "Kurz (< 4 Minuten)",
"preferences_region_label": "Land der Inhalte: ",
"preferences_quality_option_dash": "DASH (adaptive Qualität)",
"preferences_quality_option_hd720": "HD720",
"preferences_quality_option_medium": "Mittel",
"preferences_quality_option_small": "Niedrig",
"preferences_quality_dash_option_auto": "Auto",
"preferences_quality_dash_option_4320p": "4320p",
"preferences_quality_dash_option_2160p": "2160p",
"preferences_quality_dash_option_1080p": "1080p",
"preferences_quality_dash_option_720p": "720p",
"preferences_quality_dash_option_480p": "480p",
"preferences_quality_dash_option_360p": "360p",
"preferences_quality_dash_option_240p": "240p",
"preferences_quality_dash_option_144p": "144p",
"invidious": "Invidious",
"videoinfo_invidious_embed_link": "Link zum Einbetten",
"download_subtitles": "Untertitel - `x` (.vtt)",
"Video unavailable": "Video nicht verfügbar",
"user_created_playlists": "`x` Wiedergabelisten erstellt",
"user_saved_playlists": "`x` Wiedergabelisten gespeichert",
"preferences_save_player_pos_label": "Wiedergabeposition speichern: ",
"search_filters_features_option_three_sixty": "360°",
"preferences_quality_dash_option_best": "Höchste",
"preferences_quality_dash_option_worst": "Niedrigste",
"preferences_quality_dash_option_1440p": "1440p",
"videoinfo_youTube_embed_link": "Eingebettet",
"search_filters_features_option_purchased": "Gekauft",
"none": "keine",
"videoinfo_started_streaming_x_ago": "Stream begann vor `x`",
"videoinfo_watch_on_youTube": "Auf YouTube ansehen",
"preferences_quality_dash_label": "Bevorzugte DASH-Videoqualität: ",
"generic_subscribers_count": "{{count}} Abonnent",
"generic_subscribers_count_plural": "{{count}} Abonnenten",
"generic_videos_count": "{{count}} Video",
"generic_videos_count_plural": "{{count}} Videos",
"subscriptions_unseen_notifs_count": "{{count}} ungesehene Benachrichtung",
"subscriptions_unseen_notifs_count_plural": "{{count}} ungesehene Benachrichtungen",
"crash_page_refresh": "Versucht haben, <a href=\"`x`\">die Seite neu zu laden</a>",
"comments_view_x_replies": "{{count}} Antwort anzeigen",
"comments_view_x_replies_plural": "{{count}} Antworten anzeigen",
"generic_count_years": "{{count}} Jahr",
"generic_count_years_plural": "{{count}} Jahre",
"generic_count_weeks": "{{count}} Woche",
"generic_count_weeks_plural": "{{count}} Wochen",
"generic_count_days": "{{count}} Tag",
"generic_count_days_plural": "{{count}} Tage",
"crash_page_before_reporting": "Bevor Sie einen Bug melden, stellen Sie sicher, dass Sie:",
"crash_page_switch_instance": "Eine <a href=\"`x`\">andere Instanz</a> versucht haben",
"generic_count_hours": "{{count}} Stunde",
"generic_count_hours_plural": "{{count}} Stunden",
"generic_count_minutes": "{{count}} Minute",
"generic_count_minutes_plural": "{{count}} Minuten",
"crash_page_read_the_faq": "Das <a href=\"`x`\">FAQ</a> gelesen haben",
"crash_page_search_issue": "Nach <a href=\"`x`\">bereits gemeldeten Bugs auf GitHub</a> gesucht haben",
"crash_page_report_issue": "Wenn all dies nicht geholfen hat, <a href=\"`x`\">öffnen Sie bitte ein neues Problem (issue) auf Github</a> (vorzugsweise auf Englisch) und fügen Sie den folgenden Text in Ihre Nachricht ein (bitte übersetzen Sie diesen Text NICHT):",
"generic_views_count": "{{count}} Aufruf",
"generic_views_count_plural": "{{count}} Aufrufe",
"generic_count_seconds": "{{count}} Sekunde",
"generic_count_seconds_plural": "{{count}} Sekunden",
"generic_subscriptions_count": "{{count}} Abo",
"generic_subscriptions_count_plural": "{{count}} Abos",
"tokens_count": "{{count}} Token",
"tokens_count_plural": "{{count}} Tokens",
"comments_points_count": "{{count}} Punkt",
"comments_points_count_plural": "{{count}} Punkte",
"crash_page_you_found_a_bug": "Anscheinend haben Sie einen Fehler in Invidious gefunden!",
"generic_count_months": "{{count}} Monat",
"generic_count_months_plural": "{{count}} Monate",
"Cantonese (Hong Kong)": "Kantonesisch (Hong Kong)",
"Chinese (Hong Kong)": "Chinesisch (Hong Kong)",
"generic_playlists_count": "{{count}} Wiedergabeliste",
"generic_playlists_count_plural": "{{count}} Wiedergabelisten",
"preferences_watch_history_label": "Wiedergabeverlauf aktivieren: ",
"English (United Kingdom)": "Englisch (Vereinigtes Königreich)",
"English (United States)": "Englisch (Vereinigte Staaten)",
"Dutch (auto-generated)": "Niederländisch (automatisch generiert)",
"French (auto-generated)": "Französisch (automatisch generiert)",
"German (auto-generated)": "Deutsch (automatisch generiert)",
"Indonesian (auto-generated)": "Indonesisch (automatisch generiert)",
"Interlingue": "Interlingue",
"Italian (auto-generated)": "Italienisch (automatisch generiert)",
"Japanese (auto-generated)": "Japanisch (automatisch generiert)",
"Spanish (Mexico)": "Spanisch (Mexiko)",
"Spanish (Spain)": "Spanisch (Spanien)",
"Vietnamese (auto-generated)": "Vietnamesisch (automatisch generiert)",
"Russian (auto-generated)": "Russisch (automatisch generiert)",
"Chinese": "Chinesisch",
"Portuguese (Brazil)": "Portugiesisch (Brasilien)",
"Spanish (auto-generated)": "Spanisch (automatisch generiert)",
"Turkish (auto-generated)": "Türkisch (automatisch generiert)",
"Chinese (China)": "Chinesisch (China)",
"Chinese (Taiwan)": "Chinesisch (Taiwan)",
"Korean (auto-generated)": "Koreanisch (automatisch generiert)",
"Portuguese (auto-generated)": "Portugiesisch (automatisch generiert)",
"search_filters_title": "Filtern",
"search_message_change_filters_or_query": "Versuchen Sie, Ihre Suchanfrage zu erweitern und/oder die Filter zu ändern.",
"search_message_use_another_instance": " Sie können auch <a href=\"`x`\">auf einer anderen Instanz suchen</a>.",
"Popular enabled: ": "„Beliebt“-Seite aktiviert: ",
"search_message_no_results": "Keine Ergebnisse gefunden.",
"search_filters_duration_option_medium": "Mittel (4 - 20 Minuten)",
"search_filters_features_option_vr180": "VR180",
"search_filters_type_option_all": "Beliebiger Typ",
"search_filters_apply_button": "Ausgewählte Filter anwenden",
"search_filters_duration_option_none": "Beliebige Länge",
"search_filters_date_label": "Upload-Datum",
"search_filters_date_option_none": "Beliebiges Datum"
}
"Current version: ": "Aktuelle Version: "
}

View File

@ -1,10 +1,19 @@
{
"`x` subscribers": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` συνδρομητής",
"": "`x` συνδρομητές"
},
"`x` videos": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` βίντεο",
"": "`x` βίντεο"
},
"`x` playlists": "",
"LIVE": "ΖΩΝΤΑΝΑ",
"Shared `x` ago": "Μοιράστηκε πριν από `x`",
"Shared `x` ago": "Μοιράστηκε πριν `x`",
"Unsubscribe": "Απεγγραφή",
"Subscribe": "Εγγραφή",
"View channel on YouTube": "Προβολή καναλιού στο YouTube",
"View playlist on YouTube": "Προβολή καταλόγου αναπαραγωγής στο YouTube",
"View playlist on YouTube": "",
"newest": "νεότερα",
"oldest": "παλιότερα",
"popular": "δημοφιλή",
@ -21,15 +30,15 @@
"No": "Όχι",
"Import and Export Data": "Εισαγωγή και Εξαγωγή Δεδομένων",
"Import": "Εισαγωγή",
"Import Invidious data": "Εsαγωγή δεδομένων Invidious JSON",
"Import YouTube subscriptions": "Εισαγωγή συνδρομών YouTube/OPML",
"Import Invidious data": "Εισαγωγή δεδομένων Invidious",
"Import YouTube subscriptions": "Εισαγωγή συνδρομών YouTube",
"Import FreeTube subscriptions (.db)": "Εισαγωγή συνδρομών FreeTube (.db)",
"Import NewPipe subscriptions (.json)": "Εισαγωγή συνδρομών NewPipe (.json)",
"Import NewPipe data (.zip)": "Εισαγωγή δεδομένων NewPipe (.zip)",
"Export": "Εξαγωγή",
"Export subscriptions as OPML": "Εξαγωγή συνδρομών ως OPML",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Εξαγωγή συνδρομών ως OPML (για NewPipe & FreeTube)",
"Export data as JSON": "Εξαγωγή δεδομένων Invidious ως JSON",
"Export data as JSON": "Εξαγωγή δεδομένων ως JSON",
"Delete account?": "Διαγραφή λογαριασμού;",
"History": "Ιστορικό",
"An alternative front-end to YouTube": "Μία εναλλακτική πλατφόρμα για το YouTube",
@ -45,38 +54,38 @@
"Image CAPTCHA": "Εικόνα CAPTCHA",
"Sign In": "Σύνδεση",
"Register": "Εγγραφή",
"E-mail": "Ηλεκτρονικό ταχυδρομείο",
"E-mail": "E-mail",
"Google verification code": "Κωδικός επαλήθευσης Google",
"Preferences": "Προτιμήσεις",
"preferences_category_player": "Προτιμήσεις αναπαραγωγής",
"preferences_video_loop_label": "Αυτόματη επανάληψη: ",
"preferences_autoplay_label": "Αυτόματη αναπαραγωγή: ",
"preferences_continue_label": "Αναπαραγωγή επόμενου: ",
"preferences_continue_autoplay_label": "Αυτόματη αναπαραγωγή επόμενου: ",
"preferences_listen_label": "Φόρτωση μόνο ήχου: ",
"preferences_local_label": "Αναπαραγωγή με διακομιστή μεσολάβησης (proxy): ",
"preferences_speed_label": "Προεπιλεγμένη ταχύτητα: ",
"preferences_quality_label": "Προτιμώμενη ανάλυση: ",
"preferences_volume_label": "Ένταση αναπαραγωγής: ",
"preferences_comments_label": "Προεπιλεγμένα σχόλια: ",
"youtube": "YouTube",
"reddit": "Reddit",
"preferences_captions_label": "Προεπιλεγμένοι υπότιτλοι: ",
"Player preferences": "Προτιμήσεις αναπαραγωγής",
"Always loop: ": "Αυτόματη επανάληψη: ",
"Autoplay: ": "Αυτόματη αναπαραγωγή: ",
"Play next by default: ": "Αναπαραγωγή επόμενου: ",
"Autoplay next video: ": "Αυτόματη αναπαραγωγή επόμενου: ",
"Listen by default: ": "Φόρτωση μόνο ήχου: ",
"Proxy videos: ": "Αναπαραγωγή με διακομιστή μεσολάβησης (proxy): ",
"Default speed: ": "Προεπιλεγμένη ταχύτητα: ",
"Preferred video quality: ": "Προτιμώμενη ανάλυση: ",
"Player volume: ": "Ένταση αναπαραγωγής: ",
"Default comments: ": "Προεπιλεγμένα σχόλια: ",
"youtube": "youtube",
"reddit": "reddit",
"Default captions: ": "Προεπιλεγμένοι υπότιτλοι: ",
"Fallback captions: ": "Εναλλακτικοί υπότιτλοι: ",
"preferences_related_videos_label": "Προβολή σχετικών βίντεο; ",
"preferences_annotations_label": "Αυτόματη προβολή σημειώσεων: ",
"preferences_category_visual": "Προτιμήσεις εμφάνισης",
"preferences_player_style_label": "Τεχνοτροπία της συσκευής αναπαραγωγης: ",
"Show related videos: ": "Προβολή σχετικών βίντεο; ",
"Show annotations by default: ": "Αυτόματη προβολή σημειώσεων; :",
"Visual preferences": "Προτιμήσεις εμφάνισης",
"Player style: ": "",
"Dark mode: ": "Σκοτεινή λειτουργία: ",
"preferences_dark_mode_label": "Θέμα: ",
"dark": "σκοτεινό",
"light": "φωτεινό",
"preferences_thin_mode_label": "Ελαφριά λειτουργία: ",
"preferences_category_subscription": "Προτιμήσεις συνδρομών",
"preferences_annotations_subscribed_label": "Προβολή σημειώσεων μόνο για κανάλια στα οποία είστε συνδρομητής; ",
"Theme: ": "",
"dark": "",
"light": "",
"Thin mode: ": "Ελαφριά λειτουργία: ",
"Subscription preferences": "Προτιμήσεις συνδρομών",
"Show annotations by default for subscribed channels: ": "Προβολή σημειώσεων μόνο για κανάλια στα οποία είστε συνδρομητής; ",
"Redirect homepage to feed: ": "Ανακατεύθυνση αρχικής στη ροή συνδρομών: ",
"preferences_max_results_label": "Αριθμός βίντεο ανά σελίδα ροής συνδρομών: ",
"preferences_sort_label": "Ταξινόμηση ανά: ",
"Number of videos shown in feed: ": "Αριθμός βίντεο ανά σελίδα ροής συνδρομών: ",
"Sort videos by: ": "Ταξινόμηση ανά: ",
"published": "ημερομηνία δημοσίευσης",
"published - reverse": "ημερομηνία δημοσίευσης - ανάποδα",
"alphabetically": "αλφαβητικά",
@ -85,12 +94,12 @@
"channel name - reverse": "όνομα καναλιού - ανάποδα",
"Only show latest video from channel: ": "Προβολή μόνο του τελευταίου βίντεο του καναλιού: ",
"Only show latest unwatched video from channel: ": "Προβολή μόνο του τελευταίου μη-προβεβλημένου βίντεο του καναλιού: ",
"preferences_unseen_only_label": "Προβολή μόνο μη-προβεβλημένων: ",
"preferences_notifications_only_label": "Προβολή μόνο ειδοποιήσεων (αν υπάρχουν): ",
"Enable web notifications": "Ενεργοποίηση ειδοποιήσεων δικτύου",
"`x` uploaded a video": "`x` κοινοποίησε ένα βίντεο",
"`x` is live": "`x` κάνει live",
"preferences_category_data": "Προτιμήσεις δεδομένων",
"Only show unwatched: ": "Προβολή μόνο μη-προβεβλημένων: ",
"Only show notifications (if there are any): ": "Προβολή μόνο ειδοποιήσεων (αν υπάρχουν): ",
"Enable web notifications": "",
"`x` uploaded a video": "",
"`x` is live": "",
"Data preferences": "Προτιμήσεις δεδομένων",
"Clear watch history": "Εκκαθάριση ιστορικού προβολής",
"Import/export data": "Εισαγωγή/εξαγωγή δεδομένων",
"Change password": "Αλλαγή κωδικού πρόσβασης",
@ -98,9 +107,9 @@
"Manage tokens": "Διαχείριση διασυνδέσεων",
"Watch history": "Ιστορικό προβολής",
"Delete account": "Διαγραφή λογαριασμού",
"preferences_category_admin": "Προτιμήσεις διαχειριστή",
"preferences_default_home_label": "Προεπιλεγμένη αρχική: ",
"preferences_feed_menu_label": "Μενού ροής συνδρομών: ",
"Administrator preferences": "Προτιμήσεις διαχειριστή",
"Default homepage: ": "Προεπιλεγμένη αρχική: ",
"Feed menu: ": "Μενού ροής συνδρομών: ",
"Top enabled: ": "Ενεργοποίηση κορυφαίων; ",
"CAPTCHA enabled: ": "Ενεργοποίηση CAPTCHA; ",
"Login enabled: ": "Ενεργοποίηση σύνδεσης; ",
@ -110,47 +119,61 @@
"Subscription manager": "Διαχειριστής συνδρομών",
"Token manager": "Διαχειριστής διασυνδέσεων",
"Token": "Διασύνδεση",
"`x` subscriptions": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` συνδρομή",
"": "`x` συνδρομές"
},
"`x` tokens": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` διασύνδεση",
"": "`x` διασυνδέσεις"
},
"Import/export": "Εισαγωγή/εξαγωγή",
"unsubscribe": "κατάργηση συνδρομής",
"revoke": "ανάκληση",
"Subscriptions": "Συνδρομές",
"`x` unseen notifications": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` καινούρια ειδοποίηση",
"": "`x` καινούριες ειδοποιήσεις"
},
"search": "αναζήτηση",
"Log out": "Αποσύνδεση",
"Released under the AGPLv3 by Omar Roth.": "Κυκλοφορεί υπό την άδεια AGPLv3 από τον Omar Roth.",
"Source available here.": "Προβολή πηγαίου κώδικα εδώ.",
"View JavaScript license information.": "Προβολή πληροφοριών άδειας JavaScript.",
"View privacy policy.": "Προβολή πολιτικής απορρήτου.",
"Trending": "Τάσεις",
"Public": "Δημόσιο",
"Public": "",
"Unlisted": "Κρυφό",
"Private": "Ιδιωτικό",
"View all playlists": "Προβολή όλων των καταλόγων αναπαραγωγής",
"Updated `x` ago": "Ενημερώθηκε πριν από `x`",
"Delete playlist `x`?": "Διαγραφή `x` καταλόγου αναπαραγωγής;",
"Delete playlist": "Διαγραφή καταλόγου αναπαραγωγής",
"Create playlist": "Δημιουργία καταλόγου αναπαραγωγής",
"Title": "Τίτλος",
"Playlist privacy": "Ιδιωτικότητα καταλόγων αναπαραγωγής",
"Editing playlist `x`": "Επεξεργασία `x` καταλόγου αναπαραγωγής",
"Private": "",
"View all playlists": "",
"Updated `x` ago": "",
"Delete playlist `x`?": "",
"Delete playlist": "",
"Create playlist": "",
"Title": "",
"Playlist privacy": "",
"Editing playlist `x`": "",
"Watch on YouTube": "Προβολή στο YouTube",
"Hide annotations": "Απόκρυψη σημειώσεων",
"Show annotations": "Προβολή σημειώσεων",
"Genre: ": "Είδος: ",
"License: ": "Άδεια: ",
"Family friendly? ": "Φιλικό προς την οικογένεια; ",
"Wilson score: ": "Αποτελέσματα Wilson: ",
"Wilson score: ": "Wilson score: ",
"Engagement: ": "Ενδιαφέρον: ",
"Whitelisted regions: ": "Επιτρεπτές περιοχές: ",
"Blacklisted regions: ": "Μη-επιτρεπτές περιοχές: ",
"Shared `x`": "Μοιράστηκε το `x`",
"`x` views": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` προβολή",
"": "`x` προβολές"
},
"Premieres in `x`": "Πρώτη προβολή σε `x`",
"Premieres `x`": "Επίσημη πρώτη παράσταση του `x`",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Γεια! Φαίνεται πως έχετε απενεργοποιήσει το JavaScript. Πατήστε εδώ για προβολή σχολίων, αλλά έχετε υπ'όψιν σας πως ίσως φορτώσουν πιο αργά.",
"Premieres `x`": "",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Γεια! Φαίνεται πως έχετε απενεργοποιήσει το JavaScript. Πατήστε εδώ για προβολή σχολίων, αλλά έχετε υπ'όψιν σας πως ίσως φορτώσουν πιο αργά. ",
"View YouTube comments": "Προβολή σχολίων από το YouTube",
"View more comments on Reddit": "Προβολή περισσότερων σχολίων στο Reddit",
"View `x` comments": {
"([^.,0-9]|^)1([^.,0-9]|$)": "Προβολή `x` σχολίων",
"": "Προβολή `x` σχολίων"
},
"View `x` comments": "Προβολή `x` σχολίων",
"View Reddit comments": "Προβολή σχολίων από το Reddit",
"Hide replies": "Απόκρυψη απαντήσεων",
"Show replies": "Προβολή απαντήσεων",
@ -175,11 +198,19 @@
"This channel does not exist.": "Αυτό το κανάλι δεν υπάρχει.",
"Could not get channel info.": "Αδύναμια εύρεσης πληροφοριών καναλιού.",
"Could not fetch comments": "Αδυναμία λήψης σχολίων",
"View `x` replies": {
"([^.,0-9]|^)1([^.,0-9]|$)": "Προβολή `x` απάντησης",
"": "Προβολή `x` απαντήσεων"
},
"`x` ago": "Πριν `x`",
"Load more": "Φόρτωση περισσότερων",
"`x` points": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` βαθμός",
"": "`x` βαθμοί"
},
"Could not create mix.": "Αδυναμία δημιουργίας μίξης.",
"Empty playlist": "Κενή λίστα αναπαραγωγής",
"Not a playlist.": "Μη έγκυρη λίστα αναπαραγωγής.",
"Not a playlist.": "Μη έγκυρη λίστα αναπαραγωγής",
"Playlist does not exist.": "Μη υπαρκτή λίστα αναπαραγωγής.",
"Could not pull trending pages.": "Αδυναμία λήψης σελίδας τάσεων.",
"Hidden field \"challenge\" is a required field": "Το Κρυφό πεδίο \"δοκιμασία\" είναι απαραίτητο",
@ -294,12 +325,40 @@
"Yiddish": "Γίντις",
"Yoruba": "Γιορούμπα",
"Zulu": "Ζουλού",
"`x` years": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` χρόνο",
"": "`x` χρόνια"
},
"`x` months": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` μήνα",
"": "`x` μήνες"
},
"`x` weeks": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` εβδομάδα",
"": "`x` εβδομάδες"
},
"`x` days": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` ημέρα",
"": "`x` ημέρες"
},
"`x` hours": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` ώρα",
"": "`x` ώρες"
},
"`x` minutes": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` λεπτό",
"": "`x` λεπτά"
},
"`x` seconds": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` δευτερόλεπτο",
"": "`x` δευτερόλεπτα"
},
"Fallback comments: ": "Εναλλακτικά σχόλια: ",
"Popular": "Δημοφιλή",
"Top": "Κορυφαία",
"About": "Σχετικά",
"Rating: ": "Aξιολόγηση: ",
"preferences_locale_label": "Γλώσσα: ",
"Language: ": "Γλώσσα: ",
"View as playlist": "Προβολή ως λίστα αναπαραγωγής",
"Default": "Προεπιλογή",
"Music": "Μουσική",
@ -311,144 +370,12 @@
"%A %B %-d, %Y": "%A %B %-d, %Y",
"(edited)": "(τροποποιημένο)",
"YouTube comment permalink": "Σύνδεσμος YouTube σχολίου",
"permalink": "μόνιμος σύνδεσμος",
"permalink": "",
"`x` marked it with a ❤": "Ο χρηστης `x` έβαλε ❤",
"Audio mode": "Λειτουργία ήχου",
"Video mode": "Λειτουργία βίντεο",
"Videos": "Βίντεο",
"Playlists": "Λίστες Αναπαραγωγής",
"Community": "Κοινότητα",
"Current version: ": "Τρέχουσα έκδοση: ",
"generic_playlists_count": "{{count}} λίστα αναπαραγωγής",
"generic_playlists_count_plural": "{{count}} λίστες αναπαραγωγής",
"preferences_quality_dash_option_worst": "Χειρότερη",
"preferences_quality_dash_option_2160p": "2160 p",
"Video unavailable": "Το βίντεο δεν είναι διαθέσιμο",
"preferences_quality_dash_option_auto": "Αυτόματη",
"preferences_quality_dash_option_1440p": "1440p",
"preferences_quality_dash_option_1080p": "1080p",
"comments_view_x_replies": "Προβολή {{count}} απάντησης",
"comments_view_x_replies_plural": "Προβολή {{count}} απαντήσεων",
"crash_page_report_issue": "Εάν κανένα από τα παραπάνω δεν βοήθησε, παρακαλούμε <a href=\"`x`\">ανοίξτε ένα νέο θέμα στο GitHub</a> (κατά προτίμηση στα αγγλικά) και συμπεριλάβετε το ακόλουθο κείμενο στο μήνυμά σας (ΜΗΝ μεταφράζετε αυτό το κείμενο):",
"generic_count_hours": "{{count}} ώρα",
"generic_count_hours_plural": "{{count}} ώρες",
"generic_count_minutes": "{{count}} λεπτό",
"generic_count_minutes_plural": "{{count}} λεπτά",
"generic_count_seconds": "{{count}} δευτερόλεπτο",
"generic_count_seconds_plural": "{{count}} δευτερόλεπτα",
"preferences_quality_dash_label": "Προτιμώμενη ποιότητα βίντεο DASH: ",
"preferences_quality_dash_option_best": "Καλύτερη",
"preferences_quality_dash_option_480p": "480p",
"preferences_quality_dash_option_360p": "360p",
"preferences_quality_dash_option_240p": "240p",
"preferences_quality_dash_option_144p": "144p",
"generic_subscribers_count": "{{count}} συνδρομητής",
"generic_subscribers_count_plural": "{{count}} συνδρομητές",
"generic_subscriptions_count": "{{count}} συνδρομή",
"generic_subscriptions_count_plural": "{{count}} συνδρομές",
"generic_count_years": "{{count}} έτος",
"generic_count_years_plural": "{{count}} έτη",
"generic_count_months": "{{count}} μήνας",
"generic_count_months_plural": "{{count}} μήνες",
"generic_count_weeks": "{{count}} εβδομάδα",
"generic_count_weeks_plural": "{{count}} εβδομάδες",
"generic_count_days": "{{count}} ημέρα",
"generic_count_days_plural": "{{count}} ημέρες",
"crash_page_you_found_a_bug": "Φαίνεται ότι βρήκατε ένα σφάλμα στο Invidious!",
"crash_page_before_reporting": "Πριν αναφέρετε ένα σφάλμα, βεβαιωθείτε ότι έχετε:",
"crash_page_refresh": "προσπαθήσει να <a href=\"`x`\">ανανεώσετε τη σελίδα</a>",
"crash_page_read_the_faq": "διαβάσει τις <a href=\"`x`\">Συχνές Ερωτήσεις (ΣΕ)</a>",
"crash_page_search_issue": "αναζητήσει για <a href=\"`x`\">υπάρχοντα θέματα στο GitHub</a>",
"generic_views_count": "{{count}} προβολή",
"generic_views_count_plural": "{{count}} προβολές",
"generic_videos_count": "{{count}} βίντεο",
"generic_videos_count_plural": "{{count}} βίντεο",
"preferences_quality_option_hd720": "HD720",
"preferences_quality_option_medium": "Μεσαία",
"preferences_quality_option_small": "Μικρό",
"preferences_quality_option_dash": "DASH (προσαρμοστική ποιότητα)",
"preferences_quality_dash_option_4320p": "4320p",
"preferences_quality_dash_option_720p": "720p",
"invidious": "Invidious",
"preferences_region_label": "Χώρα περιεχομένου: ",
"preferences_category_misc": "Διάφορες προτιμήσεις",
"Show more": "Εμφάνιση περισσότερων",
"search_filters_date_option_today": "Σήμερα",
"search_filters_features_option_three_sixty": "360°",
"videoinfo_started_streaming_x_ago": "Ξεκίνησε η ροή `x` πριν από",
"videoinfo_watch_on_youTube": "Παρακολουθήστε στο YouTube",
"download_subtitles": "Υπότιτλοι - `x` (.vtt)",
"user_created_playlists": "`x` δημιουργημένες λίστες αναπαραγωγής",
"user_saved_playlists": "`x` αποθηκευμένες λίστες αναπαραγωγής",
"search_filters_sort_option_rating": "Αξιολόγηση",
"search_filters_sort_option_relevance": "Συνάφεια",
"search_filters_features_option_purchased": "Αγορασμένο",
"search_filters_sort_option_date": "Ημερομηνία μεταφόρτωσης",
"search_filters_type_label": "Τύπος",
"search_filters_duration_label": "Διάρκεια",
"search_filters_date_option_week": "Αυτή την εβδομάδα",
"search_filters_date_option_year": "Φέτος",
"search_filters_type_option_channel": "Κανάλι",
"search_filters_type_option_playlist": "Λίστα αναπαραγωγής",
"search_filters_duration_option_long": "Μεγάλο (> 20 λεπτά)",
"search_filters_features_option_hd": "HD",
"search_filters_features_option_location": "Τοποθεσία",
"search_filters_features_option_three_d": "3D",
"next_steps_error_message": "Μετά από αυτό θα πρέπει να προσπαθήσετε να: ",
"next_steps_error_message_go_to_youtube": "Μεταβείτε στο YouTube",
"footer_donate_page": "Δωρεά",
"footer_original_source_code": "Πρωτότυπος πηγαίος κώδικας",
"preferences_show_nick_label": "Εμφάνιση ψευδώνυμου στην κορυφή: ",
"search_filters_date_option_hour": "Τελευταία ώρα",
"adminprefs_modified_source_code_url_label": "URL σε αποθετήριο τροποποιημένου πηγαίου κώδικα",
"search_filters_features_option_subtitles": "Υπότιτλοι/CC",
"search_filters_date_option_month": "Αυτόν τον μήνα",
"Released under the AGPLv3 on Github.": "Κυκλοφορεί υπό την AGPLv3 στο GitHub.",
"search_filters_sort_label": "Ταξινόμηση κατά",
"search_filters_type_option_movie": "Ταινία",
"footer_modfied_source_code": "Τροποποιημένος πηγαίος κώδικας",
"search_filters_features_label": "Χαρακτηριστικά",
"search_filters_features_option_four_k": "4K",
"footer_documentation": "Τεκμηρίωση",
"search_filters_duration_option_short": "Σύντομο (< 4 λεπτά)",
"next_steps_error_message_refresh": "Ανανέωση",
"search_filters_type_option_video": "Βίντεο",
"search_filters_features_option_live": "Ζωντανά",
"search_filters_features_option_c_commons": "Creative Commons",
"Search": "Αναζήτηση",
"search_filters_features_option_hdr": "HDR",
"preferences_extend_desc_label": "Αυτόματη επέκταση της περιγραφής του βίντεο: ",
"preferences_vr_mode_label": "Διαδραστικά βίντεο 360 μοιρών (απαιτεί WebGL): ",
"Show less": "Εμφάνιση λιγότερων",
"footer_source_code": "Πηγαίος κώδικας",
"Chinese (Taiwan)": "Κινέζικα (Ταϊβάν)",
"Portuguese (Brazil)": "Πορτογαλικά (Βραζιλία)",
"German (auto-generated)": "Γερμανικά (αυτόματη παραγωγή)",
"Korean (auto-generated)": "Κορεάτικα (αυτόματη παραγωγή)",
"Russian (auto-generated)": "Ρωσικά (αυτόματη παραγωγή)",
"Spanish (auto-generated)": "Ισπανικά (αυτόματη παραγωγή)",
"Vietnamese (auto-generated)": "Βιετναμέζικα (αυτόματη παραγωγή)",
"English (United Kingdom)": "Αγγλικά (Ηνωμένο Βασίλειο)",
"English (United States)": "Αγγλικά (Ηνωμένων Πολιτειών)",
"Cantonese (Hong Kong)": "Καντονέζικα (Χονγκ Κονγκ)",
"Chinese": "Κινεζικά",
"Chinese (China)": "Κινέζικα (Κίνα)",
"Chinese (Hong Kong)": "Κινεζικά (Χονγκ Κονγκ)",
"Dutch (auto-generated)": "Ολαμδικά (αυτόματη παραγωγή)",
"French (auto-generated)": "Γαλλικά (αυτόματη παραγωγή)",
"Interlingue": "Ιντερλίνγκουα",
"Indonesian (auto-generated)": "Ινδονησιακά (αυτόματη παραγωγή)",
"Italian (auto-generated)": "Ιταλικά (αυτόματη παραγωγή)",
"Japanese (auto-generated)": "Ιαπωνικά (αυτόματη παραγωγή)",
"Portuguese (auto-generated)": "Πορτογαλικά (αυτόματη παραγωγή)",
"Spanish (Mexico)": "Ισπανικά (Μεξικό)",
"Spanish (Spain)": "Ισπανικά (Ισπανία)",
"Turkish (auto-generated)": "Τούρκικα (αυτόματη παραγωγή)",
"none": "κανένα",
"videoinfo_youTube_embed_link": "Ενσωμάτωση",
"videoinfo_invidious_embed_link": "Σύνδεσμος Ενσωμάτωσης",
"search_filters_type_option_show": "Μπάρα προόδου διαβάσματος",
"preferences_watch_history_label": "Ενεργοποίηση ιστορικού παρακολούθησης: ",
"search_filters_title": "Φίλτρο",
"search_message_no_results": "Δεν"
}
"Community": "",
"Current version: ": "Τρέχουσα έκδοση: "
}

View File

@ -1,14 +1,16 @@
{
"generic_views_count": "{{count}} view",
"generic_views_count_plural": "{{count}} views",
"generic_videos_count": "{{count}} video",
"generic_videos_count_plural": "{{count}} videos",
"generic_playlists_count": "{{count}} playlist",
"generic_playlists_count_plural": "{{count}} playlists",
"generic_subscribers_count": "{{count}} subscriber",
"generic_subscribers_count_plural": "{{count}} subscribers",
"generic_subscriptions_count": "{{count}} subscription",
"generic_subscriptions_count_plural": "{{count}} subscriptions",
"`x` subscribers": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` subscriber",
"": "`x` subscribers"
},
"`x` videos": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` video",
"": "`x` videos"
},
"`x` playlists": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` playlist",
"": "`x` playlists"
},
"LIVE": "LIVE",
"Shared `x` ago": "Shared `x` ago",
"Unsubscribe": "Unsubscribe",
@ -31,15 +33,15 @@
"No": "No",
"Import and Export Data": "Import and Export Data",
"Import": "Import",
"Import Invidious data": "Import Invidious JSON data",
"Import YouTube subscriptions": "Import YouTube/OPML subscriptions",
"Import Invidious data": "Import Invidious data",
"Import YouTube subscriptions": "Import YouTube subscriptions",
"Import FreeTube subscriptions (.db)": "Import FreeTube subscriptions (.db)",
"Import NewPipe subscriptions (.json)": "Import NewPipe subscriptions (.json)",
"Import NewPipe data (.zip)": "Import NewPipe data (.zip)",
"Export": "Export",
"Export subscriptions as OPML": "Export subscriptions as OPML",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Export subscriptions as OPML (for NewPipe & FreeTube)",
"Export data as JSON": "Export Invidious data as JSON",
"Export data as JSON": "Export data as JSON",
"Delete account?": "Delete account?",
"History": "History",
"An alternative front-end to YouTube": "An alternative front-end to YouTube",
@ -58,59 +60,35 @@
"E-mail": "E-mail",
"Google verification code": "Google verification code",
"Preferences": "Preferences",
"preferences_category_player": "Player preferences",
"preferences_video_loop_label": "Always loop: ",
"preferences_autoplay_label": "Autoplay: ",
"preferences_continue_label": "Play next by default: ",
"preferences_continue_autoplay_label": "Autoplay next video: ",
"preferences_listen_label": "Listen by default: ",
"preferences_local_label": "Proxy videos: ",
"preferences_watch_history_label": "Enable watch history: ",
"preferences_speed_label": "Default speed: ",
"preferences_quality_label": "Preferred video quality: ",
"preferences_quality_option_dash": "DASH (adaptive quality)",
"preferences_quality_option_hd720": "HD720",
"preferences_quality_option_medium": "Medium",
"preferences_quality_option_small": "Small",
"preferences_quality_dash_label": "Preferred DASH video quality: ",
"preferences_quality_dash_option_auto": "Auto",
"preferences_quality_dash_option_best": "Best",
"preferences_quality_dash_option_worst": "Worst",
"preferences_quality_dash_option_4320p": "4320p",
"preferences_quality_dash_option_2160p": "2160p",
"preferences_quality_dash_option_1440p": "1440p",
"preferences_quality_dash_option_1080p": "1080p",
"preferences_quality_dash_option_720p": "720p",
"preferences_quality_dash_option_480p": "480p",
"preferences_quality_dash_option_360p": "360p",
"preferences_quality_dash_option_240p": "240p",
"preferences_quality_dash_option_144p": "144p",
"preferences_volume_label": "Player volume: ",
"preferences_comments_label": "Default comments: ",
"youtube": "YouTube",
"reddit": "Reddit",
"invidious": "Invidious",
"preferences_captions_label": "Default captions: ",
"Player preferences": "Player preferences",
"Always loop: ": "Always loop: ",
"Autoplay: ": "Autoplay: ",
"Play next by default: ": "Play next by default: ",
"Autoplay next video: ": "Autoplay next video: ",
"Listen by default: ": "Listen by default: ",
"Proxy videos: ": "Proxy videos: ",
"Default speed: ": "Default speed: ",
"Preferred video quality: ": "Preferred video quality: ",
"Player volume: ": "Player volume: ",
"Default comments: ": "Default comments: ",
"youtube": "youtube",
"reddit": "reddit",
"Default captions: ": "Default captions: ",
"Fallback captions: ": "Fallback captions: ",
"preferences_related_videos_label": "Show related videos: ",
"preferences_annotations_label": "Show annotations by default: ",
"preferences_extend_desc_label": "Automatically extend video description: ",
"preferences_vr_mode_label": "Interactive 360 degree videos (requires WebGL): ",
"preferences_category_visual": "Visual preferences",
"preferences_region_label": "Content country: ",
"preferences_player_style_label": "Player style: ",
"Show related videos: ": "Show related videos: ",
"Show annotations by default: ": "Show annotations by default: ",
"Visual preferences": "Visual preferences",
"Player style: ": "Player style: ",
"Dark mode: ": "Dark mode: ",
"preferences_dark_mode_label": "Theme: ",
"Theme: ": "Theme: ",
"dark": "dark",
"light": "light",
"preferences_thin_mode_label": "Thin mode: ",
"preferences_category_misc": "Miscellaneous preferences",
"preferences_automatic_instance_redirect_label": "Automatic instance redirection (fallback to redirect.invidious.io): ",
"preferences_category_subscription": "Subscription preferences",
"preferences_annotations_subscribed_label": "Show annotations by default for subscribed channels? ",
"Thin mode: ": "Thin mode: ",
"Subscription preferences": "Subscription preferences",
"Show annotations by default for subscribed channels: ": "Show annotations by default for subscribed channels? ",
"Redirect homepage to feed: ": "Redirect homepage to feed: ",
"preferences_max_results_label": "Number of videos shown in feed: ",
"preferences_sort_label": "Sort videos by: ",
"Number of videos shown in feed: ": "Number of videos shown in feed: ",
"Sort videos by: ": "Sort videos by: ",
"published": "published",
"published - reverse": "published - reverse",
"alphabetically": "alphabetically",
@ -119,12 +97,12 @@
"channel name - reverse": "channel name - reverse",
"Only show latest video from channel: ": "Only show latest video from channel: ",
"Only show latest unwatched video from channel: ": "Only show latest unwatched video from channel: ",
"preferences_unseen_only_label": "Only show unwatched: ",
"preferences_notifications_only_label": "Only show notifications (if there are any): ",
"Only show unwatched: ": "Only show unwatched: ",
"Only show notifications (if there are any): ": "Only show notifications (if there are any): ",
"Enable web notifications": "Enable web notifications",
"`x` uploaded a video": "`x` uploaded a video",
"`x` is live": "`x` is live",
"preferences_category_data": "Data preferences",
"Data preferences": "Data preferences",
"Clear watch history": "Clear watch history",
"Import/export data": "Import/export data",
"Change password": "Change password",
@ -132,11 +110,9 @@
"Manage tokens": "Manage tokens",
"Watch history": "Watch history",
"Delete account": "Delete account",
"preferences_category_admin": "Administrator preferences",
"preferences_default_home_label": "Default homepage: ",
"preferences_feed_menu_label": "Feed menu: ",
"preferences_show_nick_label": "Show nickname on top: ",
"Popular enabled: ": "Popular enabled: ",
"Administrator preferences": "Administrator preferences",
"Default homepage: ": "Default homepage: ",
"Feed menu: ": "Feed menu: ",
"Top enabled: ": "Top enabled: ",
"CAPTCHA enabled: ": "CAPTCHA enabled: ",
"Login enabled: ": "Login enabled: ",
@ -146,17 +122,25 @@
"Subscription manager": "Subscription manager",
"Token manager": "Token manager",
"Token": "Token",
"tokens_count": "{{count}} token",
"tokens_count_plural": "{{count}} tokens",
"`x` subscriptions": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` subscription",
"": "`x` subscriptions"
},
"`x` tokens": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` token",
"": "`x` tokens"
},
"Import/export": "Import/export",
"unsubscribe": "unsubscribe",
"revoke": "revoke",
"Subscriptions": "Subscriptions",
"subscriptions_unseen_notifs_count": "{{count}} unseen notification",
"subscriptions_unseen_notifs_count_plural": "{{count}} unseen notifications",
"`x` unseen notifications": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` unseen notification",
"": "`x` unseen notifications"
},
"search": "search",
"Log out": "Log out",
"Released under the AGPLv3 on Github.": "Released under the AGPLv3 on GitHub.",
"Released under the AGPLv3 by Omar Roth.": "Released under the AGPLv3 by Omar Roth.",
"Source available here.": "Source available here.",
"View JavaScript license information.": "View JavaScript license information.",
"View privacy policy.": "View privacy policy.",
@ -172,13 +156,7 @@
"Title": "Title",
"Playlist privacy": "Playlist privacy",
"Editing playlist `x`": "Editing playlist `x`",
"Show more": "Show more",
"Show less": "Show less",
"Watch on YouTube": "Watch on YouTube",
"Switch Invidious Instance": "Switch Invidious Instance",
"search_message_no_results": "No results found.",
"search_message_change_filters_or_query": "Try widening your search query and/or changing the filters.",
"search_message_use_another_instance": " You can also <a href=\"`x`\">search on another instance</a>.",
"Hide annotations": "Hide annotations",
"Show annotations": "Show annotations",
"Genre: ": "Genre: ",
@ -189,6 +167,10 @@
"Whitelisted regions: ": "Whitelisted regions: ",
"Blacklisted regions: ": "Blacklisted regions: ",
"Shared `x`": "Shared `x`",
"`x` views": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` view",
"": "`x` views"
},
"Premieres in `x`": "Premieres in `x`",
"Premieres `x`": "Premieres `x`",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.",
@ -222,12 +204,16 @@
"This channel does not exist.": "This channel does not exist.",
"Could not get channel info.": "Could not get channel info.",
"Could not fetch comments": "Could not fetch comments",
"comments_view_x_replies": "View {{count}} reply",
"comments_view_x_replies_plural": "View {{count}} replies",
"View `x` replies": {
"([^.,0-9]|^)1([^.,0-9]|$)": "View `x` reply",
"": "View `x` replies"
},
"`x` ago": "`x` ago",
"Load more": "Load more",
"comments_points_count": "{{count}} point",
"comments_points_count_plural": "{{count}} points",
"`x` points": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` point",
"": "`x` points"
},
"Could not create mix.": "Could not create mix.",
"Empty playlist": "Empty playlist",
"Not a playlist.": "Not a playlist.",
@ -240,8 +226,6 @@
"No such user": "No such user",
"Token is expired, please try again": "Token is expired, please try again",
"English": "English",
"English (United Kingdom)": "English (United Kingdom)",
"English (United States)": "English (United States)",
"English (auto-generated)": "English (auto-generated)",
"Afrikaans": "Afrikaans",
"Albanian": "Albanian",
@ -255,31 +239,23 @@
"Bosnian": "Bosnian",
"Bulgarian": "Bulgarian",
"Burmese": "Burmese",
"Cantonese (Hong Kong)": "Cantonese (Hong Kong)",
"Catalan": "Catalan",
"Cebuano": "Cebuano",
"Chinese": "Chinese",
"Chinese (China)": "Chinese (China)",
"Chinese (Hong Kong)": "Chinese (Hong Kong)",
"Chinese (Simplified)": "Chinese (Simplified)",
"Chinese (Taiwan)": "Chinese (Taiwan)",
"Chinese (Traditional)": "Chinese (Traditional)",
"Corsican": "Corsican",
"Croatian": "Croatian",
"Czech": "Czech",
"Danish": "Danish",
"Dutch": "Dutch",
"Dutch (auto-generated)": "Dutch (auto-generated)",
"Esperanto": "Esperanto",
"Estonian": "Estonian",
"Filipino": "Filipino",
"Finnish": "Finnish",
"French": "French",
"French (auto-generated)": "French (auto-generated)",
"Galician": "Galician",
"Georgian": "Georgian",
"German": "German",
"German (auto-generated)": "German (auto-generated)",
"Greek": "Greek",
"Gujarati": "Gujarati",
"Haitian Creole": "Haitian Creole",
@ -292,19 +268,14 @@
"Icelandic": "Icelandic",
"Igbo": "Igbo",
"Indonesian": "Indonesian",
"Indonesian (auto-generated)": "Indonesian (auto-generated)",
"Interlingue": "Interlingue",
"Irish": "Irish",
"Italian": "Italian",
"Italian (auto-generated)": "Italian (auto-generated)",
"Japanese": "Japanese",
"Japanese (auto-generated)": "Japanese (auto-generated)",
"Javanese": "Javanese",
"Kannada": "Kannada",
"Kazakh": "Kazakh",
"Khmer": "Khmer",
"Korean": "Korean",
"Korean (auto-generated)": "Korean (auto-generated)",
"Kurdish": "Kurdish",
"Kyrgyz": "Kyrgyz",
"Lao": "Lao",
@ -327,12 +298,9 @@
"Persian": "Persian",
"Polish": "Polish",
"Portuguese": "Portuguese",
"Portuguese (auto-generated)": "Portuguese (auto-generated)",
"Portuguese (Brazil)": "Portuguese (Brazil)",
"Punjabi": "Punjabi",
"Romanian": "Romanian",
"Russian": "Russian",
"Russian (auto-generated)": "Russian (auto-generated)",
"Samoan": "Samoan",
"Scottish Gaelic": "Scottish Gaelic",
"Serbian": "Serbian",
@ -344,10 +312,7 @@
"Somali": "Somali",
"Southern Sotho": "Southern Sotho",
"Spanish": "Spanish",
"Spanish (auto-generated)": "Spanish (auto-generated)",
"Spanish (Latin America)": "Spanish (Latin America)",
"Spanish (Mexico)": "Spanish (Mexico)",
"Spanish (Spain)": "Spanish (Spain)",
"Sundanese": "Sundanese",
"Swahili": "Swahili",
"Swedish": "Swedish",
@ -356,39 +321,50 @@
"Telugu": "Telugu",
"Thai": "Thai",
"Turkish": "Turkish",
"Turkish (auto-generated)": "Turkish (auto-generated)",
"Ukrainian": "Ukrainian",
"Urdu": "Urdu",
"Uzbek": "Uzbek",
"Vietnamese": "Vietnamese",
"Vietnamese (auto-generated)": "Vietnamese (auto-generated)",
"Welsh": "Welsh",
"Western Frisian": "Western Frisian",
"Xhosa": "Xhosa",
"Yiddish": "Yiddish",
"Yoruba": "Yoruba",
"Zulu": "Zulu",
"generic_count_years": "{{count}} year",
"generic_count_years_plural": "{{count}} years",
"generic_count_months": "{{count}} month",
"generic_count_months_plural": "{{count}} months",
"generic_count_weeks": "{{count}} week",
"generic_count_weeks_plural": "{{count}} weeks",
"generic_count_days": "{{count}} day",
"generic_count_days_plural": "{{count}} days",
"generic_count_hours": "{{count}} hour",
"generic_count_hours_plural": "{{count}} hours",
"generic_count_minutes": "{{count}} minute",
"generic_count_minutes_plural": "{{count}} minutes",
"generic_count_seconds": "{{count}} second",
"generic_count_seconds_plural": "{{count}} seconds",
"`x` years": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` year",
"": "`x` years"
},
"`x` months": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` month",
"": "`x` months"
},
"`x` weeks": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` week",
"": "`x` weeks"
},
"`x` days": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` day",
"": "`x` days"
},
"`x` hours": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` hour",
"": "`x` hours"
},
"`x` minutes": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` minute",
"": "`x` minutes"
},
"`x` seconds": {
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` second",
"": "`x` seconds"
},
"Fallback comments: ": "Fallback comments: ",
"Popular": "Popular",
"Search": "Search",
"Top": "Top",
"About": "About",
"Rating: ": "Rating: ",
"preferences_locale_label": "Language: ",
"Language: ": "Language: ",
"View as playlist": "View as playlist",
"Default": "Default",
"Music": "Music",
@ -407,69 +383,5 @@
"Videos": "Videos",
"Playlists": "Playlists",
"Community": "Community",
"search_filters_title": "Filters",
"search_filters_date_label": "Upload date",
"search_filters_date_option_none": "Any date",
"search_filters_date_option_hour": "Last Hour",
"search_filters_date_option_today": "Today",
"search_filters_date_option_week": "This week",
"search_filters_date_option_month": "This month",
"search_filters_date_option_year": "This year",
"search_filters_type_label": "Type",
"search_filters_type_option_all": "Any type",
"search_filters_type_option_video": "Video",
"search_filters_type_option_channel": "Channel",
"search_filters_type_option_playlist": "Playlist",
"search_filters_type_option_movie": "Movie",
"search_filters_type_option_show": "Show",
"search_filters_duration_label": "Duration",
"search_filters_duration_option_none": "Any duration",
"search_filters_duration_option_short": "Short (< 4 minutes)",
"search_filters_duration_option_medium": "Medium (4 - 20 minutes)",
"search_filters_duration_option_long": "Long (> 20 minutes)",
"search_filters_features_label": "Features",
"search_filters_features_option_live": "Live",
"search_filters_features_option_four_k": "4K",
"search_filters_features_option_hd": "HD",
"search_filters_features_option_subtitles": "Subtitles/CC",
"search_filters_features_option_c_commons": "Creative Commons",
"search_filters_features_option_three_sixty": "360°",
"search_filters_features_option_vr180": "VR180",
"search_filters_features_option_three_d": "3D",
"search_filters_features_option_hdr": "HDR",
"search_filters_features_option_location": "Location",
"search_filters_features_option_purchased": "Purchased",
"search_filters_sort_label": "Sort By",
"search_filters_sort_option_relevance": "Relevance",
"search_filters_sort_option_rating": "Rating",
"search_filters_sort_option_date": "Upload Date",
"search_filters_sort_option_views": "View count",
"search_filters_apply_button": "Apply selected filters",
"Current version: ": "Current version: ",
"next_steps_error_message": "After which you should try to: ",
"next_steps_error_message_refresh": "Refresh",
"next_steps_error_message_go_to_youtube": "Go to YouTube",
"footer_donate_page": "Donate",
"footer_documentation": "Documentation",
"footer_source_code": "Source code",
"footer_original_source_code": "Original source code",
"footer_modfied_source_code": "Modified Source code",
"adminprefs_modified_source_code_url_label": "URL to modified source code repository",
"none": "none",
"videoinfo_started_streaming_x_ago": "Started streaming `x` ago",
"videoinfo_watch_on_youTube": "Watch on YouTube",
"videoinfo_youTube_embed_link": "Embed",
"videoinfo_invidious_embed_link": "Embed Link",
"download_subtitles": "Subtitles - `x` (.vtt)",
"user_created_playlists": "`x` created playlists",
"user_saved_playlists": "`x` saved playlists",
"Video unavailable": "Video unavailable",
"preferences_save_player_pos_label": "Save playback position: ",
"crash_page_you_found_a_bug": "It looks like you found a bug in Invidious!",
"crash_page_before_reporting": "Before reporting a bug, make sure that you have:",
"crash_page_refresh": "tried to <a href=\"`x`\">refresh the page</a>",
"crash_page_switch_instance": "tried to <a href=\"`x`\">use another instance</a>",
"crash_page_read_the_faq": "read the <a href=\"`x`\">Frequently Asked Questions (FAQ)</a>",
"crash_page_search_issue": "searched for <a href=\"`x`\">existing issues on GitHub</a>",
"crash_page_report_issue": "If none of the above helped, please <a href=\"`x`\">open a new issue on GitHub</a> (preferably in English) and include the following text in your message (do NOT translate that text):"
}
"Current version: ": "Current version: "
}

View File

@ -1,10 +1,13 @@
{
"`x` subscribers": "`x` abonantoj",
"`x` videos": "`x` filmetoj",
"`x` playlists": "`x` ludlistoj",
"LIVE": "NUNA",
"Shared `x` ago": "Konigita antaŭ `x`",
"Unsubscribe": "Malabonu",
"Subscribe": "Abonu",
"View channel on YouTube": "Vidu kanalon en JuTubo",
"View playlist on YouTube": "Vidu ludliston en JuTubo",
"Unsubscribe": "Malaboni",
"Subscribe": "Aboni",
"View channel on YouTube": "Vidi kanalon en JuTubo",
"View playlist on YouTube": "Vidi ludliston en JuTubo",
"newest": "pli novaj",
"oldest": "pli malnovaj",
"popular": "popularaj",
@ -48,39 +51,35 @@
"E-mail": "Retpoŝto",
"Google verification code": "Kontrolkodo de Google",
"Preferences": "Agordoj",
"preferences_category_player": "Spektilaj agordoj",
"preferences_video_loop_label": "Ĉiam ripeti: ",
"preferences_autoplay_label": "Aŭtomate ludi: ",
"preferences_continue_label": "Ludi sekvan defaŭlte: ",
"preferences_continue_autoplay_label": "Aŭtomate ludi sekvan filmeton: ",
"preferences_listen_label": "Aŭskulti defaŭlte: ",
"preferences_local_label": "Ĉu uzi prokuran servilon por filmetojn? ",
"preferences_speed_label": "Defaŭlta rapido: ",
"preferences_quality_label": "Preferita filmetkvalito: ",
"preferences_volume_label": "Ludila sonforteco: ",
"preferences_comments_label": "Defaŭltaj komentoj: ",
"Player preferences": "Spektilaj agordoj",
"Always loop: ": "Ĉiam ripeti: ",
"Autoplay: ": "Aŭtomate ludi: ",
"Play next by default: ": "Ludi sekvan defaŭlte: ",
"Autoplay next video: ": "Aŭtomate ludi sekvan filmeton: ",
"Listen by default: ": "Aŭskulti defaŭlte: ",
"Proxy videos: ": "Ĉu uzi prokuran servilon por filmetojn? ",
"Default speed: ": "Defaŭlta rapido: ",
"Preferred video quality: ": "Preferita filmetkvalito: ",
"Player volume: ": "Ludila sonforteco: ",
"Default comments: ": "Defaŭltaj komentoj: ",
"youtube": "JuTubo",
"reddit": "Reddit",
"preferences_captions_label": "Defaŭltaj subtekstoj: ",
"Default captions: ": "Defaŭltaj subtekstoj: ",
"Fallback captions: ": "Retrodefaŭltaj subtekstoj: ",
"preferences_related_videos_label": "Ĉu montri rilatajn filmetojn? ",
"preferences_annotations_label": "Ĉu montri prinotojn defaŭlte? ",
"preferences_extend_desc_label": "Aŭtomate etendi priskribon de filmeto: ",
"preferences_vr_mode_label": "Interagaj 360-gradaj filmetoj: ",
"preferences_category_visual": "Vidaj preferoj",
"preferences_player_style_label": "Ludila stilo: ",
"Show related videos: ": "Ĉu montri rilatajn filmetojn? ",
"Show annotations by default: ": "Ĉu montri prinotojn defaŭlte? ",
"Visual preferences": "Vidaj preferoj",
"Player style: ": "Ludila stilo: ",
"Dark mode: ": "Malhela reĝimo: ",
"preferences_dark_mode_label": "Etoso: ",
"Theme: ": "Etoso: ",
"dark": "malhela",
"light": "hela",
"preferences_thin_mode_label": "Maldika reĝimo: ",
"preferences_category_misc": "Aliaj agordoj",
"preferences_automatic_instance_redirect_label": "Aŭtomata alidirektado de instalaĵo (retropaŝo al redirect.invidious.io): ",
"preferences_category_subscription": "Abonaj agordoj",
"preferences_annotations_subscribed_label": "Ĉu montri prinotojn defaŭlte por abonitaj kanaloj? ",
"Thin mode: ": "Maldika reĝimo: ",
"Subscription preferences": "Abonaj agordoj",
"Show annotations by default for subscribed channels: ": "Ĉu montri prinotojn defaŭlte por abonitaj kanaloj? ",
"Redirect homepage to feed: ": "Alidirekti hejmpâgon al fluo: ",
"preferences_max_results_label": "Nombro da filmetoj montritaj en fluo: ",
"preferences_sort_label": "Ordi filmetojn per: ",
"Number of videos shown in feed: ": "Nombro da filmetoj montritaj en fluo: ",
"Sort videos by: ": "Ordi filmetojn per: ",
"published": "publikigo",
"published - reverse": "publitigo - renverse",
"alphabetically": "alfabete",
@ -89,12 +88,12 @@
"channel name - reverse": "kanala nombro - renverse",
"Only show latest video from channel: ": "Nur montri pli novan filmeton el kanalo: ",
"Only show latest unwatched video from channel: ": "Nur montri pli novan malviditan filmeton el kanalo: ",
"preferences_unseen_only_label": "Nur montri malviditajn: ",
"preferences_notifications_only_label": "Nur montri sciigojn (se estas): ",
"Only show unwatched: ": "Nur montri malviditajn: ",
"Only show notifications (if there are any): ": "Nur montri sciigojn (se estas): ",
"Enable web notifications": "Ebligi retejajn sciigojn",
"`x` uploaded a video": "`x` alŝutis filmeton",
"`x` is live": "`x` estas nuna",
"preferences_category_data": "Datumagordoj",
"Data preferences": "Datumagordoj",
"Clear watch history": "Forigi vidohistorion",
"Import/export data": "Importi/Eksporti datumojn",
"Change password": "Ŝanĝi pasvorton",
@ -102,10 +101,9 @@
"Manage tokens": "Administri ĵetonojn",
"Watch history": "Vidohistorio",
"Delete account": "Forigi konton",
"preferences_category_admin": "Agordoj de administranto",
"preferences_default_home_label": "Defaŭlta hejmpaĝo: ",
"preferences_feed_menu_label": "Flua menuo: ",
"preferences_show_nick_label": "Montri kromnomon supre: ",
"Administrator preferences": "Agordoj de administranto",
"Default homepage: ": "Defaŭlta hejmpaĝo: ",
"Feed menu: ": "Flua menuo: ",
"Top enabled: ": "Ĉu pli bonaj ŝaltitaj? ",
"CAPTCHA enabled: ": "Ĉu CAPTCHA ŝaltita? ",
"Login enabled: ": "Ĉu ensaluto aktivita? ",
@ -115,13 +113,16 @@
"Subscription manager": "Administrilo de abonoj",
"Token manager": "Ĵetona administrilo",
"Token": "Ĵetono",
"`x` subscriptions": "`x` abonoj",
"`x` tokens": "`x` ĵetonoj",
"Import/export": "Importi/Eksporti",
"unsubscribe": "malabonu",
"unsubscribe": "malaboni",
"revoke": "senvalidigi",
"Subscriptions": "Abonoj",
"`x` unseen notifications": "`x` neviditaj sciigoj",
"search": "serĉi",
"Log out": "Elsaluti",
"Released under the AGPLv3 on Github.": "Eldonita sub la AGPLv3 en GitHub.",
"Released under the AGPLv3 by Omar Roth.": "Eldonita sub la AGPLv3 de Omar Roth.",
"Source available here.": "Fonto havebla ĉi tie.",
"View JavaScript license information.": "Vidi Ĝavoskriptan licencan informon.",
"View privacy policy.": "Vidi regularon pri privateco.",
@ -137,10 +138,7 @@
"Title": "Titolo",
"Playlist privacy": "Privateco de ludlisto",
"Editing playlist `x`": "Redaktante ludlisto `x`",
"Show more": "Montri pli",
"Show less": "Montri malpli",
"Watch on YouTube": "Vidi filmeton en JuTubo",
"Switch Invidious Instance": "Ŝanĝi instalaĵon de Indivious",
"Hide annotations": "Kaŝi prinotojn",
"Show annotations": "Montri prinotojn",
"Genre: ": "Ĝenro: ",
@ -151,15 +149,13 @@
"Whitelisted regions: ": "Regionoj listigitaj en blanka listo: ",
"Blacklisted regions: ": "Regionoj listigitaj en nigra listo: ",
"Shared `x`": "Konigita `x`",
"`x` views": "`x` spektaĵoj",
"Premieres in `x`": "Premieras en `x`",
"Premieres `x`": "Premieras `x`",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Saluton! Ŝajnas, ke vi havas Ĝavoskripton malebligitan. Klaku ĉi tie por vidi komentojn, memoru, ke la ŝargado povus daŭri iom pli.",
"View YouTube comments": "Vidi komentojn de JuTubo",
"View more comments on Reddit": "Vidi pli komentoj en Reddit",
"View `x` comments": {
"([^.,0-9]|^)1([^.,0-9]|$)": "Vidi `x` komentojn",
"": "Vidi `x` komentojn"
},
"View `x` comments": "Vidi `x` komentojn",
"View Reddit comments": "Vidi komentojn de Reddit",
"Hide replies": "Kaŝi respondojn",
"Show replies": "Montri respondojn",
@ -184,8 +180,10 @@
"This channel does not exist.": "Ĉi tiu kanalo ne ekzistas.",
"Could not get channel info.": "Ne povis havigi kanalan informon.",
"Could not fetch comments": "Ne povis venigi komentojn",
"View `x` replies": "Vidi `x` respondojn",
"`x` ago": "antaŭ `x`",
"Load more": "Ŝarĝi pli",
"`x` points": "`x` poentoj",
"Could not create mix.": "Ne povis krei mikson.",
"Empty playlist": "Ludlisto estas malplena",
"Not a playlist.": "Nevalida ludlisto.",
@ -303,16 +301,22 @@
"Yiddish": "Jida",
"Yoruba": "Joruba",
"Zulu": "Zulua",
"`x` years": "`x` jaroj",
"`x` months": "`x` monatoj",
"`x` weeks": "`x` semajnoj",
"`x` days": "`x` tagoj",
"`x` hours": "`x` horoj",
"`x` minutes": "`x` minutoj",
"`x` seconds": "`x` sekundoj",
"Fallback comments: ": "Retrodefaŭltaj komentoj: ",
"Popular": "Popularaj",
"Search": "Serĉi",
"Top": "Supraj",
"About": "Pri",
"Rating: ": "Takso: ",
"preferences_locale_label": "Lingvo: ",
"Language: ": "Lingvo: ",
"View as playlist": "Vidi kiel ludlisto",
"Default": "Defaŭlte",
"Music": "Muziko",
"Music": "Musiko",
"Gaming": "Komputiloludoj",
"News": "Novaĵoj",
"Movies": "Filmoj",
@ -328,45 +332,5 @@
"Videos": "Filmetoj",
"Playlists": "Ludlistoj",
"Community": "Komunumo",
"search_filters_sort_option_relevance": "rilateco",
"search_filters_sort_option_rating": "takso",
"search_filters_sort_option_date": "dato",
"search_filters_sort_option_views": "vidoj",
"search_filters_type_label": "enhavtipo",
"search_filters_duration_label": "daŭro",
"search_filters_features_label": "trajtoj",
"search_filters_sort_label": "ordigi",
"search_filters_date_option_hour": "horo",
"search_filters_date_option_today": "hodiaŭ",
"search_filters_date_option_week": "semajno",
"search_filters_date_option_month": "monato",
"search_filters_date_option_year": "jaro",
"search_filters_type_option_video": "filmeto",
"search_filters_type_option_channel": "kanalo",
"search_filters_type_option_playlist": "ludlisto",
"search_filters_type_option_movie": "filmo",
"search_filters_type_option_show": "spektaĵo",
"search_filters_features_option_hd": "altdistingiva",
"search_filters_features_option_subtitles": "subtekstoj",
"search_filters_features_option_c_commons": "Krea Komunaĵo",
"search_filters_features_option_three_d": "3D",
"search_filters_features_option_live": "nuna",
"search_filters_features_option_four_k": "4k",
"search_filters_features_option_location": "loko",
"search_filters_features_option_hdr": "granddinamikgama",
"Current version: ": "Nuna versio: ",
"next_steps_error_message": "Poste, vi provu: ",
"next_steps_error_message_refresh": "Reŝargi",
"next_steps_error_message_go_to_youtube": "Iri al JuTubo",
"search_filters_duration_option_long": "Longa (> 20 minutos)",
"search_filters_duration_option_short": "Mallonga (< 4 minutos)",
"footer_documentation": "Dokumentaro",
"footer_source_code": "Fontkodo",
"adminprefs_modified_source_code_url_label": "URL al modifita deponejo de fontkodo",
"footer_modfied_source_code": "Modifita Fontkodo",
"footer_original_source_code": "Originala fontkodo",
"footer_donate_page": "Donaci",
"preferences_region_label": "Lando de la enhavo: ",
"preferences_quality_dash_label": "Preferata DASH-a videkvalito: ",
"search_filters_title": "Filtri"
}
"Current version: ": "Nuna versio: "
}

View File

@ -1,4 +1,7 @@
{
"`x` subscribers": "`x` suscriptores",
"`x` videos": "`x` vídeos",
"`x` playlists": "`x` listas de reproducción",
"LIVE": "DIRECTO",
"Shared `x` ago": "Compartido hace `x`",
"Unsubscribe": "Desuscribirse",
@ -21,15 +24,15 @@
"No": "No",
"Import and Export Data": "Importación y exportación de datos",
"Import": "Importar",
"Import Invidious data": "Importar datos JSON de Invidious",
"Import YouTube subscriptions": "Importar suscripciones de YouTube/OPML",
"Import Invidious data": "Importar datos de Invidious",
"Import YouTube subscriptions": "Importar suscripciones de YouTube",
"Import FreeTube subscriptions (.db)": "Importar suscripciones de FreeTube (.db)",
"Import NewPipe subscriptions (.json)": "Importar suscripciones de NewPipe (.json)",
"Import NewPipe data (.zip)": "Importar datos de NewPipe (.zip)",
"Export": "Exportar",
"Export subscriptions as OPML": "Exportar suscripciones como OPML",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Exportar suscripciones como OPML (para NewPipe y FreeTube)",
"Export data as JSON": "Exportar datos de Invidious como JSON",
"Export data as JSON": "Exportar datos como JSON",
"Delete account?": "¿Quiere borrar la cuenta?",
"History": "Historial",
"An alternative front-end to YouTube": "Una interfaz alternativa para YouTube",
@ -48,39 +51,35 @@
"E-mail": "Correo",
"Google verification code": "Código de verificación de Google",
"Preferences": "Preferencias",
"preferences_category_player": "Preferencias del reproductor",
"preferences_video_loop_label": "Repetir siempre: ",
"preferences_autoplay_label": "Reproducción automática: ",
"preferences_continue_label": "Reproducir siguiente por defecto: ",
"preferences_continue_autoplay_label": "Reproducir automáticamente el vídeo siguiente: ",
"preferences_listen_label": "Activar el sonido por defecto: ",
"preferences_local_label": "¿Usar un proxy para los vídeos? ",
"preferences_speed_label": "Velocidad por defecto: ",
"preferences_quality_label": "Calidad de vídeo preferida: ",
"preferences_volume_label": "Volumen del reproductor: ",
"preferences_comments_label": "Comentarios por defecto: ",
"Player preferences": "Preferencias del reproductor",
"Always loop: ": "Repetir siempre: ",
"Autoplay: ": "Reproducción automática: ",
"Play next by default: ": "Reproducir siguiente por defecto: ",
"Autoplay next video: ": "Reproducir automáticamente el vídeo siguiente: ",
"Listen by default: ": "Activar el sonido por defecto: ",
"Proxy videos: ": "¿Usar un proxy para los vídeos? ",
"Default speed: ": "Velocidad por defecto: ",
"Preferred video quality: ": "Calidad de vídeo preferida: ",
"Player volume: ": "Volumen del reproductor: ",
"Default comments: ": "Comentarios por defecto: ",
"youtube": "YouTube",
"reddit": "Reddit",
"preferences_captions_label": "Subtítulos por defecto: ",
"Default captions: ": "Subtítulos por defecto: ",
"Fallback captions: ": "Subtítulos alternativos: ",
"preferences_related_videos_label": "¿Mostrar vídeos relacionados? ",
"preferences_annotations_label": "¿Mostrar anotaciones por defecto? ",
"preferences_extend_desc_label": "Extender automáticamente la descripción del vídeo: ",
"preferences_vr_mode_label": "Vídeos interactivos de 360 grados (necesita WebGL): ",
"preferences_category_visual": "Preferencias visuales",
"preferences_player_style_label": "Estilo de reproductor: ",
"Show related videos: ": "¿Mostrar vídeos relacionados? ",
"Show annotations by default: ": "¿Mostrar anotaciones por defecto? ",
"Visual preferences": "Preferencias visuales",
"Player style: ": "Estilo de reproductor: ",
"Dark mode: ": "Modo oscuro: ",
"preferences_dark_mode_label": "Tema: ",
"Theme: ": "Tema: ",
"dark": "oscuro",
"light": "claro",
"preferences_thin_mode_label": "Modo compacto: ",
"preferences_category_misc": "Preferencias misceláneas",
"preferences_automatic_instance_redirect_label": "Redirección automática de instancia (segunda opción a redirect.invidious.io): ",
"preferences_category_subscription": "Preferencias de la suscripción",
"preferences_annotations_subscribed_label": "¿Mostrar anotaciones por defecto para los canales suscritos? ",
"Thin mode: ": "Modo compacto: ",
"Subscription preferences": "Preferencias de la suscripción",
"Show annotations by default for subscribed channels: ": "¿Mostrar anotaciones por defecto para los canales suscritos? ",
"Redirect homepage to feed: ": "Redirigir la página de inicio a la fuente: ",
"preferences_max_results_label": "Número de vídeos mostrados en la fuente: ",
"preferences_sort_label": "Ordenar los vídeos por: ",
"Number of videos shown in feed: ": "Número de vídeos mostrados en la fuente: ",
"Sort videos by: ": "Ordenar los vídeos por: ",
"published": "fecha de publicación",
"published - reverse": "fecha de publicación: orden inverso",
"alphabetically": "alfabéticamente",
@ -89,12 +88,12 @@
"channel name - reverse": "nombre del canal: orden inverso",
"Only show latest video from channel: ": "Mostrar solo el último vídeo del canal: ",
"Only show latest unwatched video from channel: ": "Mostrar solo el último vídeo sin ver del canal: ",
"preferences_unseen_only_label": "Mostrar solo los no vistos: ",
"preferences_notifications_only_label": "Mostrar solo notificaciones (si hay alguna): ",
"Only show unwatched: ": "Mostrar solo los no vistos: ",
"Only show notifications (if there are any): ": "Mostrar solo notificaciones (si hay alguna): ",
"Enable web notifications": "Habilitar notificaciones web",
"`x` uploaded a video": "`x` subió un video",
"`x` is live": "`x` esta en vivo",
"preferences_category_data": "Preferencias de los datos",
"Data preferences": "Preferencias de los datos",
"Clear watch history": "Borrar el historial de reproducción",
"Import/export data": "Importar/Exportar datos",
"Change password": "Cambiar contraseña",
@ -102,10 +101,9 @@
"Manage tokens": "Gestionar tokens",
"Watch history": "Historial de reproducción",
"Delete account": "Borrar cuenta",
"preferences_category_admin": "Preferencias de administrador",
"preferences_default_home_label": "Página de inicio por defecto: ",
"preferences_feed_menu_label": "Menú de fuentes: ",
"preferences_show_nick_label": "Mostrar nombre de usuario arriba: ",
"Administrator preferences": "Preferencias de administrador",
"Default homepage: ": "Página de inicio por defecto: ",
"Feed menu: ": "Menú de fuentes: ",
"Top enabled: ": "¿Habilitar los destacados? ",
"CAPTCHA enabled: ": "¿Habilitar los CAPTCHA? ",
"Login enabled: ": "¿Habilitar el inicio de sesión? ",
@ -115,13 +113,16 @@
"Subscription manager": "Gestor de suscripciones",
"Token manager": "Gestor de tokens",
"Token": "Token",
"`x` subscriptions": "`x` suscripciones",
"`x` tokens": "`x` tokens",
"Import/export": "Importar/Exportar",
"unsubscribe": "Desuscribirse",
"revoke": "revocar",
"Subscriptions": "Suscripciones",
"`x` unseen notifications": "`x` notificaciones sin ver",
"search": "buscar",
"Log out": "Cerrar la sesión",
"Released under the AGPLv3 on Github.": "Publicado bajo la AGPLv3 en GitHub.",
"Released under the AGPLv3 by Omar Roth.": "Publicado bajo licencia AGPLv3 por Omar Roth.",
"Source available here.": "Código fuente disponible aquí.",
"View JavaScript license information.": "Ver información de licencia de JavaScript.",
"View privacy policy.": "Ver la política de privacidad.",
@ -131,16 +132,13 @@
"Private": "Privado",
"View all playlists": "Ver todas las listas de reproducción",
"Updated `x` ago": "Actualizado hace `x`",
"Delete playlist `x`?": "¿Borrar la lista de reproducción `x`?",
"Delete playlist": "Borrar lista de reproducción",
"Delete playlist `x`?": "¿Eliminar la lista de reproducción `x`?",
"Delete playlist": "Eliminar lista de reproducción",
"Create playlist": "Crear lista de reproducción",
"Title": "Título",
"Playlist privacy": "Privacidad de la lista de reproducción",
"Editing playlist `x`": "Editando la lista de reproducción 'x'",
"Show more": "Mostrar más",
"Show less": "Mostrar menos",
"Watch on YouTube": "Ver el vídeo en YouTube",
"Switch Invidious Instance": "Cambiar Instancia de Invidious",
"Watch on YouTube": "Ver el vídeo en Youtube",
"Hide annotations": "Ocultar anotaciones",
"Show annotations": "Mostrar anotaciones",
"Genre: ": "Género: ",
@ -151,15 +149,13 @@
"Whitelisted regions: ": "Regiones permitidas: ",
"Blacklisted regions: ": "Regiones bloqueadas: ",
"Shared `x`": "Compartido `x`",
"`x` views": "`x` visualizaciones",
"Premieres in `x`": "Se estrena en `x`",
"Premieres `x`": "Estrenos `x`",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "¡Hola! Parece que tiene JavaScript desactivado. Haga clic aquí para ver los comentarios, pero tenga en cuenta que pueden tardar un poco más en cargarse.",
"View YouTube comments": "Ver los comentarios de YouTube",
"View more comments on Reddit": "Ver más comentarios en Reddit",
"View `x` comments": {
"([^.,0-9]|^)1([^.,0-9]|$)": "Ver `x` comentarios",
"": "Ver `x` comentarios"
},
"View `x` comments": "Ver `x` comentarios",
"View Reddit comments": "Ver los comentarios de Reddit",
"Hide replies": "Ocultar las respuestas",
"Show replies": "Mostrar las respuestas",
@ -184,8 +180,10 @@
"This channel does not exist.": "El canal no existe.",
"Could not get channel info.": "No se ha podido obtener información del canal.",
"Could not fetch comments": "No se han podido recuperar los comentarios",
"View `x` replies": "Ver `x` respuestas",
"`x` ago": "hace `x`",
"Load more": "Cargar más",
"`x` points": "`x` puntos",
"Could not create mix.": "No se ha podido crear la mezcla.",
"Empty playlist": "La lista de reproducción está vacía",
"Not a playlist.": "Lista de reproducción no válida.",
@ -195,10 +193,10 @@
"Hidden field \"token\" is a required field": "El campo oculto «símbolo» es un campo obligatorio",
"Erroneous challenge": "Desafío no válido",
"Erroneous token": "Símbolo no válido",
"No such user": "Usuario no existe",
"No such user": "Usuario no válido",
"Token is expired, please try again": "El símbolo ha caducado, inténtelo de nuevo",
"English": "Inglés",
"English (auto-generated)": "Inglés (generados automáticamente)",
"English (auto-generated)": "Inglés (autogenerado)",
"Afrikaans": "Afrikáans",
"Albanian": "Albanés",
"Amharic": "Amárico",
@ -303,13 +301,19 @@
"Yiddish": "Yidis",
"Yoruba": "Yoruba",
"Zulu": "Zulú",
"`x` years": "`x` años",
"`x` months": "`x` meses",
"`x` weeks": "`x` semanas",
"`x` days": "`x` días",
"`x` hours": "`x` horas",
"`x` minutes": "`x` minutos",
"`x` seconds": "`x` segundos",
"Fallback comments: ": "Comentarios alternativos: ",
"Popular": "Populares",
"Search": "Buscar",
"Top": "Destacados",
"About": "Acerca de",
"Rating: ": "Valoración: ",
"preferences_locale_label": "Idioma: ",
"Language: ": "Idioma: ",
"View as playlist": "Ver como lista de reproducción",
"Default": "Por defecto",
"Music": "Música",
@ -321,154 +325,12 @@
"%A %B %-d, %Y": "%A %B %-d, %Y",
"(edited)": "(editado)",
"YouTube comment permalink": "Enlace permanente de YouTube del comentario",
"permalink": "enlace permanente",
"permalink": "permalink",
"`x` marked it with a ❤": "`x` lo ha marcado con un ❤",
"Audio mode": "Modo de audio",
"Video mode": "Modo de vídeo",
"Videos": "Vídeos",
"Playlists": "Listas de reproducción",
"Community": "Comunidad",
"search_filters_sort_option_relevance": "relevancia",
"search_filters_sort_option_rating": "valoración",
"search_filters_sort_option_date": "fecha",
"search_filters_sort_option_views": "visualizaciones",
"search_filters_type_label": "content_type",
"search_filters_duration_label": "duración",
"search_filters_features_label": "funcionalidades",
"search_filters_sort_label": "ordenar",
"search_filters_date_option_hour": "hora",
"search_filters_date_option_today": "hoy",
"search_filters_date_option_week": "semana",
"search_filters_date_option_month": "mes",
"search_filters_date_option_year": "año",
"search_filters_type_option_video": "vídeo",
"search_filters_type_option_channel": "canal",
"search_filters_type_option_playlist": "lista de reproducción",
"search_filters_type_option_movie": "película",
"search_filters_type_option_show": "programa",
"search_filters_features_option_hd": "hd",
"search_filters_features_option_subtitles": "subtítulos",
"search_filters_features_option_c_commons": "creative_commons",
"search_filters_features_option_three_d": "3d",
"search_filters_features_option_live": "directo",
"search_filters_features_option_four_k": "4k",
"search_filters_features_option_location": "ubicación",
"search_filters_features_option_hdr": "hdr",
"Current version: ": "Versión actual: ",
"next_steps_error_message": "Después de lo cual deberías intentar: ",
"next_steps_error_message_refresh": "Recargar la página",
"next_steps_error_message_go_to_youtube": "Ir a YouTube",
"search_filters_duration_option_short": "Corto (< 4 minutos)",
"search_filters_duration_option_long": "Largo (> 20 minutos)",
"footer_documentation": "Documentación",
"footer_original_source_code": "Código fuente original",
"adminprefs_modified_source_code_url_label": "URL al repositorio de código fuente modificado",
"footer_source_code": "Código fuente",
"footer_modfied_source_code": "Código fuente modificado",
"footer_donate_page": "Donar",
"preferences_region_label": "País del contenido: ",
"preferences_quality_dash_label": "Calidad de vídeo DASH preferida: ",
"preferences_quality_option_hd720": "HD720",
"preferences_quality_option_medium": "Intermedia",
"preferences_quality_dash_option_auto": "Automática",
"none": "ninguno",
"videoinfo_started_streaming_x_ago": "Comenzó difusión hace `x`",
"download_subtitles": "Subtítulos- `x` (.vtt)",
"user_created_playlists": "`x` listas de reproducción creadas",
"user_saved_playlists": "`x` listas de reproducción guardadas",
"Video unavailable": "Vídeo no disponible",
"videoinfo_youTube_embed_link": "Insertar",
"preferences_quality_dash_option_2160p": "2160p",
"preferences_quality_dash_option_4320p": "4320p",
"invidious": "Invidious",
"preferences_quality_dash_option_480p": "480p",
"preferences_quality_option_dash": "DASH (calidad adaptativa)",
"preferences_quality_dash_option_720p": "720p",
"preferences_quality_dash_option_360p": "360p",
"preferences_quality_dash_option_240p": "240p",
"preferences_quality_dash_option_144p": "144p",
"preferences_quality_option_small": "Pequeña",
"preferences_quality_dash_option_1440p": "1440p",
"preferences_quality_dash_option_best": "La mejor",
"preferences_quality_dash_option_worst": "La peor",
"videoinfo_invidious_embed_link": "Enlace para Insertar",
"preferences_quality_dash_option_1080p": "1080p",
"search_filters_features_option_purchased": "Comprado",
"search_filters_features_option_three_sixty": "360°",
"videoinfo_watch_on_youTube": "Ver en YouTube",
"preferences_save_player_pos_label": "Guardar posición de reproducción: ",
"generic_views_count": "{{count}} visualización",
"generic_views_count_plural": "{{count}} visualizaciones",
"generic_subscribers_count": "{{count}} suscriptor",
"generic_subscribers_count_plural": "{{count}} suscriptores",
"generic_subscriptions_count": "{{count}} suscripción",
"generic_subscriptions_count_plural": "{{count}} suscripciones",
"subscriptions_unseen_notifs_count": "{{count}} notificación no vista",
"subscriptions_unseen_notifs_count_plural": "{{count}} notificaciones no vistas",
"generic_count_days": "{{count}} día",
"generic_count_days_plural": "{{count}} días",
"comments_view_x_replies": "Ver {{count}} respuesta",
"comments_view_x_replies_plural": "Ver {{count}} respuestas",
"generic_count_weeks": "{{count}} semana",
"generic_count_weeks_plural": "{{count}} semanas",
"generic_playlists_count": "{{count}} lista de reproducción",
"generic_playlists_count_plural": "{{count}} listas de reproducción",
"generic_videos_count": "{{count}} vídeo",
"generic_videos_count_plural": "{{count}} vídeos",
"generic_count_months": "{{count}} mes",
"generic_count_months_plural": "{{count}} meses",
"comments_points_count": "{{count}} punto",
"comments_points_count_plural": "{{count}} puntos",
"generic_count_years": "{{count}} año",
"generic_count_years_plural": "{{count}} años",
"generic_count_hours": "{{count}} hora",
"generic_count_hours_plural": "{{count}} horas",
"generic_count_minutes": "{{count}} minuto",
"generic_count_minutes_plural": "{{count}} minutos",
"generic_count_seconds": "{{count}} segundo",
"generic_count_seconds_plural": "{{count}} segundos",
"crash_page_before_reporting": "Antes de notificar un error asegúrate de que has:",
"crash_page_switch_instance": "probado a <a href=\"`x`\">usar otra instancia</a>",
"crash_page_read_the_faq": "leído las <a href=\"`x`\">Preguntas Frecuentes</a>",
"crash_page_search_issue": "buscado <a href=\"`x`\">problemas existentes en GitHub</a>",
"crash_page_you_found_a_bug": "¡Parece que has encontrado un error en Invidious!",
"crash_page_refresh": "probado a <a href=\"`x`\">recargar la página</a>",
"crash_page_report_issue": "Si nada de lo anterior ha sido de ayuda, por favor, <a href=\"`x`\">abre una nueva incidencia en GitHub</a> (preferiblemente en inglés) e incluye el siguiente texto en tu mensaje (NO traduzcas este texto):",
"English (United States)": "Inglés (Estados Unidos)",
"Cantonese (Hong Kong)": "Cantonés (Hong Kong)",
"Dutch (auto-generated)": "Neerlandés (generados automáticamente)",
"French (auto-generated)": "Francés (generados automáticamente)",
"Interlingue": "Occidental",
"Japanese (auto-generated)": "Japonés (generados automáticamente)",
"Russian (auto-generated)": "Ruso (generados automáticamente)",
"Spanish (Spain)": "Español (España)",
"Vietnamese (auto-generated)": "Vietnamita (generados automáticamente)",
"English (United Kingdom)": "Inglés (Reino Unido)",
"Chinese (Taiwan)": "Chino (Taiwán)",
"German (auto-generated)": "Alemán (generados automáticamente)",
"Italian (auto-generated)": "Italiano (generados automáticamente)",
"Turkish (auto-generated)": "Turco (generados automáticamente)",
"Portuguese (Brazil)": "Portugués (Brasil)",
"Indonesian (auto-generated)": "Indonesio (generados automáticamente)",
"Portuguese (auto-generated)": "Portugués (generados automáticamente)",
"Chinese": "Chino",
"Chinese (Hong Kong)": "Chino (Hong Kong)",
"Chinese (China)": "Chino (China)",
"Korean (auto-generated)": "Coreano (generados automáticamente)",
"Spanish (Mexico)": "Español (Méjico)",
"Spanish (auto-generated)": "Español (generados automáticamente)",
"preferences_watch_history_label": "Habilitar historial de reproducciones: ",
"search_message_no_results": "No se han encontrado resultados.",
"search_message_change_filters_or_query": "Pruebe ampliar la consulta de búsqueda y/o a cambiar los filtros.",
"search_filters_title": "Filtros",
"search_filters_date_label": "Fecha de subida",
"search_filters_date_option_none": "Cualquier fecha",
"search_filters_type_option_all": "Cualquier tipo",
"search_filters_duration_option_none": "Cualquier duración",
"search_filters_features_option_vr180": "VR180",
"search_filters_apply_button": "Aplicar filtros seleccionados",
"tokens_count": "{{count}} token",
"tokens_count_plural": "{{count}} tokens",
"search_message_use_another_instance": " También puede <a href=\"`x`\">buscar en otra instancia</a>.",
"search_filters_duration_option_medium": "Medio (4 - 20 minutes)"
}
"Current version: ": "Versión actual: "
}

View File

@ -1,338 +0,0 @@
{
"generic_playlists_count": "{{count}} esitusloend",
"generic_playlists_count_plural": "{{count}} esindusloendit",
"LIVE": "OTSEÜLEKANNE",
"View channel on YouTube": "Vaata kanalit YouTube'is",
"Log in": "Logi sisse",
"Log in/register": "Logi sisse/registreeru",
"Dark mode: ": "Tume režiim: ",
"generic_videos_count": "{{count}} video",
"generic_videos_count_plural": "{{count}} videot",
"generic_subscribers_count": "{{count}} tellija",
"generic_subscribers_count_plural": "{{count}} tellijat",
"generic_subscriptions_count": "{{count}} tellimus",
"generic_subscriptions_count_plural": "{{count}} tellimust",
"Shared `x` ago": "Jagatud `x` tagasi",
"Unsubscribe": "Loobu tellimusest",
"Subscribe": "Telli",
"View playlist on YouTube": "Vaata esitusloendit YouTube'is",
"newest": "uusimad",
"oldest": "vanimad",
"popular": "populaarsed",
"last": "viimane",
"Next page": "Järgmine leht",
"Previous page": "Eelmine leht",
"Clear watch history?": "Kustuta vaatamiste ajalugu?",
"New password": "Uus salasõna",
"New passwords must match": "Uued salasõnad peavad ühtima",
"Cannot change password for Google accounts": "Google'i kasutaja salasõna ei saa muuta",
"Import and Export Data": "Impordi ja ekspordi andmed",
"Import": "Impordi",
"Import YouTube subscriptions": "Impordi tellimused Youtube'ist/OPML-ist",
"Import FreeTube subscriptions (.db)": "Impordi tellimused FreeTube'ist (.db)",
"Import NewPipe data (.zip)": "Impordi NewPipe'i andmed (.zip)",
"Export": "Ekspordi",
"Export subscriptions as OPML": "Ekspordi tellimused OPML-ina",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Ekspordi tellimused OPML-ina (NewPipe'i ja FreeTube'i jaoks)",
"Delete account?": "Kustuta kasutaja?",
"History": "Ajalugu",
"JavaScript license information": "JavaScripti litsentsi info",
"source": "allikas",
"Log in with Google": "Logi sisse Google'iga",
"User ID": "Kasutada ID",
"Password": "Salasõna",
"Time (h:mm:ss):": "Aeg (h:mm:ss):",
"Text CAPTCHA": "CAPTCHA-tekst",
"Image CAPTCHA": "CAPTCHA-foto",
"Sign In": "Logi sisse",
"Register": "Registreeru",
"E-mail": "E-post",
"Preferences": "Eelistused",
"preferences_category_player": "Mängija eelistused",
"preferences_continue_autoplay_label": "Mängi järgmine video automaatselt: ",
"preferences_quality_label": "Eelistatud videokvaliteet: ",
"preferences_quality_option_dash": "DASH (kohanduv kvaliteet)",
"preferences_quality_option_hd720": "HD720",
"preferences_quality_option_medium": "Keskmine",
"preferences_quality_option_small": "Väike",
"preferences_quality_dash_label": "Eelistatav DASH-video kvaliteet: ",
"preferences_quality_dash_option_auto": "Automaatne",
"preferences_quality_dash_option_best": "Parim",
"preferences_quality_dash_option_worst": "Halvim",
"preferences_volume_label": "Video helitugevus: ",
"youtube": "YouTube",
"reddit": "Reddit",
"preferences_related_videos_label": "Näita sarnaseid videosid: ",
"preferences_vr_mode_label": "Interaktiivne 360-kraadine video (vajalik WebGL): ",
"preferences_dark_mode_label": "Teema: ",
"dark": "tume",
"light": "hele",
"preferences_category_subscription": "Tellimuse seaded",
"preferences_max_results_label": "Avalehel näidatavate videote arv: ",
"preferences_sort_label": "Sorteeri: ",
"published": "avaldatud",
"alphabetically": "tähestikulises järjekorras",
"alphabetically - reverse": "vastupidi tähestikulises järjekorras",
"channel name": "kanali nimi",
"preferences_unseen_only_label": "Näita ainult vaatamata videosid: ",
"Only show latest video from channel: ": "Näita ainult viimast videot: ",
"preferences_notifications_only_label": "Näita ainult teavitusi (kui neid on): ",
"Enable web notifications": "Luba veebiteavitused",
"`x` uploaded a video": "`x` laadis video üles",
"`x` is live": "`x` teeb otseülekannet",
"preferences_category_data": "Andme-eelistused",
"Clear watch history": "Puhasta vaatamisajalugu",
"Import/export data": "Impordi/ekspordi andmed",
"Change password": "Muuda salasõna",
"Watch history": "Vaatamisajalugu",
"Delete account": "Kustuta kasutaja",
"Save preferences": "Salvesta eelistused",
"Token": "Token",
"Import/export": "Imprort/eksport",
"unsubscribe": "loobu tellimusest",
"Subscriptions": "Tellimused",
"search": "otsi",
"Source available here.": "Allikas on kättesaadaval siin.",
"View privacy policy.": "Vaata privaatsuspoliitikat.",
"Public": "Avalik",
"Private": "Privaatne",
"View all playlists": "Vaata kõiki esitusloendeid",
"Updated `x` ago": "Uuendas `x` tagasi",
"Delete playlist `x`?": "Kustuta esitusloend `x`?",
"Delete playlist": "Kustuta esitusloend",
"Create playlist": "Loo esitlusloend",
"Title": "Pealkiri",
"Playlist privacy": "Esitusloendi privaatsus",
"Show more": "Näita rohkem",
"Show less": "Näita vähem",
"Watch on YouTube": "Vaata YouTube'is",
"search_message_no_results": "Tulemusi ei leitud.",
"search_message_change_filters_or_query": "Proovi otsingut laiendada või filtreid muuta.",
"Genre: ": "Žanr: ",
"License: ": "Litsents: ",
"Family friendly? ": "Peresõbralik? ",
"Shared `x`": "Jagas `x`",
"Premieres in `x`": "Esilinastub `x`",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Tundub, et oled JavaScripti välja lülitanud. Vajuta siia, et kommentaare vaadata; nende laadimine võib võtta natukene rohkem aega.",
"View Reddit comments": "Vaata Redditi kommentaare",
"Hide replies": "Peida vastused",
"Show replies": "Näita vastuseid",
"Incorrect password": "Vale salasõna",
"Login failed. This may be because two-factor authentication is not turned on for your account.": "Sisselogimine ei õnnestunud. Asi võib olla selles, et",
"Wrong answer": "Vale vastus",
"User ID is a required field": "Kasutaja ID on kohustuslik väli",
"Password is a required field": "Salasõna on kohustuslik väli",
"Wrong username or password": "Vale kasutajanimi või salasõna",
"Please sign in using 'Log in with Google'": "Palun kasutage 'Logi sisse Google'iga'",
"Password cannot be longer than 55 characters": "Salasõna ei tohi olla pikem kui 55 tähemärki",
"Password cannot be empty": "Salasõna ei tohi olla tühi",
"Please log in": "Palun logige sisse",
"channel:`x`": "kanal:`x`",
"Deleted or invalid channel": "Kanal on kustutatud või seda ei leitud",
"This channel does not exist.": "Sellist kanalit pole olemas.",
"comments_view_x_replies": "{{count}} vastus",
"comments_view_x_replies_plural": "{{count}} vastust",
"`x` ago": "`x` tagasi",
"Load more": "Laadi rohkem",
"Empty playlist": "Tühi esitusloend",
"Not a playlist.": "Tegu pole esitusloendiga.",
"Playlist does not exist.": "Seda esitusloendit pole olemas.",
"No such user": "Sellist kasutajat pole",
"English": "Inglise",
"English (United Kingdom)": "Inglise (Suurbritannia)",
"English (United States)": "Inglise (USA)",
"English (auto-generated)": "Inglise (automaatselt koostatud)",
"Afrikaans": "Afrikaani",
"Albanian": "Albaania",
"Arabic": "Araabia",
"Armenian": "Armeenia",
"Bangla": "Bengali",
"Basque": "Baski",
"Belarusian": "Valgevene",
"Bulgarian": "Bulgaaria",
"Burmese": "Birma",
"Cantonese (Hong Kong)": "Kantoni (Hong Konk)",
"Chinese (China)": "Hiina (Hiina)",
"Chinese (Hong Kong)": "Hiina (Hong Kong)",
"Chinese (Simplified)": "Hiina (lihtsustatud)",
"Chinese (Taiwan)": "Hiina (Taiwan)",
"Croatian": "Horvaatia",
"Czech": "Tšehhi",
"Danish": "Taani",
"Dutch": "Hollandi",
"Esperanto": "Esperanto",
"Estonian": "Eesti",
"Filipino": "Filipiini",
"Finnish": "Soome",
"French": "Prantsuse",
"French (auto-generated)": "Prantsuse (automaatne)",
"Dutch (auto-generated)": "Hollandi (automaatne)",
"Galician": "Kaliitsia",
"Georgian": "Gruusia",
"Haitian Creole": "Haiti kreool",
"Hausa": "Hausa",
"Hawaiian": "Havaii",
"Hebrew": "Heebrea",
"Hindi": "Hindi",
"Hungarian": "Ungari",
"Icelandic": "Islandi",
"Indonesian": "Indoneesia",
"Japanese (auto-generated)": "Jaapani (automaatne)",
"Kannada": "Kannada",
"Kazakh": "Kasahhi",
"Luxembourgish": "Luksemburgi",
"Macedonian": "Makedoonia",
"Malay": "Malai",
"Maltese": "Malta",
"Maori": "Maori",
"Marathi": "Marathi",
"Mongolian": "Mongoli",
"Nepali": "Nepaali",
"Norwegian Bokmål": "Norra (Bokmål)",
"Persian": "Pärsia",
"Polish": "Poola",
"Portuguese": "Portugali",
"Portuguese (auto-generated)": "Portugali (automaatne)",
"Portuguese (Brazil)": "Portugali (Brasiilia)",
"Romanian": "Rumeenia",
"Russian": "Vene",
"Russian (auto-generated)": "Vene (automaatne)",
"Scottish Gaelic": "Šoti (Gaeli)",
"Serbian": "Serbia",
"Slovak": "Slovaki",
"Slovenian": "Sloveeni",
"Somali": "Somaali",
"Spanish": "Hispaania",
"Spanish (auto-generated)": "Hispaania (automaatne)",
"Spanish (Latin America)": "Hispaania (Ladina-Ameerika)",
"Spanish (Mexico)": "Hispaania (Mehhiko)",
"Spanish (Spain)": "Hispaania (Hispaania)",
"Swahili": "Suahili",
"Swedish": "Rootsi",
"Tajik": "Tadžiki",
"Tamil": "Tamiili",
"Thai": "Tai",
"Turkish": "Türgi",
"Turkish (auto-generated)": "Türgi (automaatne)",
"Ukrainian": "Ukraina",
"Uzbek": "Usbeki",
"Vietnamese": "Vietnami",
"Vietnamese (auto-generated)": "Vietnami (automaatne)",
"generic_count_years": "{{count}} aasta",
"generic_count_years_plural": "{{count}} aastat",
"generic_count_months": "{{count}} kuu",
"generic_count_months_plural": "{{count}} kuud",
"generic_count_weeks": "{{count}} nädal",
"generic_count_weeks_plural": "{{count}} nädalat",
"generic_count_days": "{{count}} päev",
"generic_count_days_plural": "{{count}} päeva",
"generic_count_hours": "{{count}} tund",
"generic_count_hours_plural": "{{count}} tundi",
"generic_count_minutes": "{{count}} minut",
"generic_count_minutes_plural": "{{count}} minutit",
"Popular": "Populaarne",
"Search": "Otsi",
"Top": "Top",
"About": "Leheküljest",
"preferences_locale_label": "Keel: ",
"View as playlist": "Vaata esitusloendina",
"Movies": "Filmid",
"Download as: ": "Laadi kui: ",
"(edited)": "(muudetud)",
"`x` marked it with a ❤": "`x` märkis ❤",
"Audio mode": "Audiorežiim",
"Video mode": "Videorežiim",
"search_filters_date_label": "Üleslaadimise kuupäev",
"search_filters_date_option_none": "Ükskõik mis kuupäev",
"search_filters_date_option_today": "Täna",
"search_filters_date_option_week": "Sel nädalal",
"search_filters_date_option_hour": "Viimasel tunnil",
"search_filters_date_option_month": "Sel kuul",
"search_filters_date_option_year": "Sel aastal",
"search_filters_type_label": "Tüüp",
"search_filters_type_option_all": "Ükskõik mis tüüp",
"search_filters_duration_label": "Kestus",
"search_filters_type_option_show": "Näita",
"search_filters_duration_option_none": "Ükskõik mis kestus",
"search_filters_duration_option_short": "Lühike (alla 4 minuti)",
"search_filters_duration_option_medium": "Keskmine (4 - 20 minutit)",
"search_filters_duration_option_long": "Pikk (üle 20 minuti)",
"search_filters_features_option_live": "Otseülekanne",
"search_filters_features_option_four_k": "4K",
"search_filters_features_option_hd": "HD",
"search_filters_features_option_subtitles": "Subtiitrid",
"search_filters_features_option_location": "Asukoht",
"search_filters_sort_label": "Sorteeri",
"search_filters_sort_option_views": "Vaatamiste arv",
"next_steps_error_message": "Pärast mida võiksite proovida: ",
"videoinfo_started_streaming_x_ago": "Alustas otseülekannet `x` tagasi",
"Yes": "Jah",
"generic_views_count": "{{count}} vaatamine",
"generic_views_count_plural": "{{count}} vaatamist",
"Import NewPipe subscriptions (.json)": "Impordi tellimused NewPipe'ist (.json)",
"No": "Ei",
"preferences_region_label": "Riik: ",
"View YouTube comments": "Vaata YouTube'i kommentaare",
"preferences_extend_desc_label": "Ava video kirjeldus automaatselt: ",
"German (auto-generated)": "Saksa (automaatne)",
"Italian": "Itaalia",
"preferences_player_style_label": "Mängija stiil: ",
"subscriptions_unseen_notifs_count": "{{count}} lugemata teavitus",
"subscriptions_unseen_notifs_count_plural": "{{count}} lugemata teavitust",
"View more comments on Reddit": "Vaata teisi kommentaare Redditis",
"Only show latest unwatched video from channel: ": "Näita ainult viimast vaatamata videot: ",
"tokens_count": "{{count}} token",
"tokens_count_plural": "{{count}} tokenit",
"Log out": "Logi välja",
"Premieres `x`": "Linastub`x`",
"View `x` comments": {
"([^.,0-9]|^)1([^.,0-9]|$)": "Vaata `x` kommentaari",
"": "Vaata `x` kommentaare"
},
"Khmer": "Khmeeri",
"Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "Sisselogimine ei õnnestunud. Kontrollige, kas two-factor authentication (Authenticator või SMS) on sisselülitatud.",
"Invalid TFA code": "Vale TFA-kood",
"Bosnian": "Bosnia",
"Corsican": "Korsika",
"Javanese": "Jaava",
"Lithuanian": "Leedu",
"Videos": "Videod",
"Community": "Kogukond",
"CAPTCHA is a required field": "CAPTCHA on kohustuslik väli",
"comments_points_count": "{{count}} punkt",
"comments_points_count_plural": "{{count}} punkti",
"Chinese": "Hiina",
"German": "Saksa",
"Indonesian (auto-generated)": "Indoneesia (automaatne)",
"Italian (auto-generated)": "Itaalia (automaatne)",
"Kyrgyz": "Kirkiisi",
"Latin": "Ladina",
"generic_count_seconds": "{{count}} sekund",
"generic_count_seconds_plural": "{{count}} sekundit",
"Catalan": "Katalaani",
"Chinese (Traditional)": "Hiina (traditsiooniline)",
"Greek": "Kreeka",
"Kurdish": "Kurdi",
"Latvian": "Läti",
"Irish": "Iiri",
"Korean": "Korea",
"Japanese": "Jaapani",
"Korean (auto-generated)": "Korea (automaatne)",
"Music": "Muusika",
"Playlists": "Esitusloendid",
"search_filters_type_option_video": "Video",
"search_filters_sort_option_date": "Üleslaadimise kuupäev",
"Current version: ": "Praegune versioon: ",
"footer_documentation": "Dokumentatsioon",
"Gaming": "Mängud",
"News": "Uudised",
"Download": "Laadi alla",
"search_filters_title": "Filtrid",
"search_filters_type_option_channel": "Kanal",
"search_filters_type_option_playlist": "Esitusloend",
"search_filters_type_option_movie": "Film",
"next_steps_error_message_go_to_youtube": "Minna YouTube'i",
"next_steps_error_message_refresh": "Laadida uuesti",
"footer_donate_page": "Anneta",
"videoinfo_watch_on_youTube": "Vaata YouTube'is"
}

View File

@ -1,4 +1,7 @@
{
"`x` subscribers": "`x` harpidedun",
"`x` videos": "`x` bideo",
"`x` playlists": "`x` erreprodukzio-zerrenda",
"LIVE": "ZUZENEAN",
"Shared `x` ago": "Duela `x` partekatua",
"Unsubscribe": "Harpidetza kendu",
@ -16,19 +19,20 @@
"New passwords must match": "Pasahitza berriek bat egin behar dute",
"Cannot change password for Google accounts": "Ezin da pasahitza aldatu Google kontuetan",
"Authorize token?": "Baimendu tokena?",
"Authorize token for `x`?": "",
"Yes": "Bai",
"No": "Ez",
"Import and Export Data": "Datuak inportatu eta esportatu",
"Import": "Inportatu",
"Import Invidious data": "Inportatu Invidiouseko JSON datuak",
"Import YouTube subscriptions": "Inportatu YouTubeko/OPML harpidetzak",
"Import Invidious data": "Inportatu Invidiouseko datuak",
"Import YouTube subscriptions": "Inportatu YouTubeko harpidetzak",
"Import FreeTube subscriptions (.db)": "Inportatu FreeTubeko harpidetzak (.db)",
"Import NewPipe subscriptions (.json)": "Inportatu NewPipeko harpidetzak (.json)",
"Import NewPipe data (.zip)": "Inportatu NewPipeko datuak (.zip)",
"Export": "Esportatu",
"Export subscriptions as OPML": "Esportatu harpidetzak OPML bezala",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Esportatu harpidetzak OPML bezala (NewPipe eta FreeTuberako)",
"Export data as JSON": "Esportatu Invidious datuak JSON gisa",
"Export data as JSON": "Esportatu datuak JSON bezala",
"Delete account?": "Kontua ezabatu?",
"History": "Historia",
"An alternative front-end to YouTube": "YouTuberako interfaze alternatibo bat",
@ -45,233 +49,288 @@
"Sign In": "Hasi saioa",
"Register": "Eman izena",
"E-mail": "E-posta",
"Google verification code": "",
"Preferences": "Hobespenak",
"preferences_category_player": "Erreproduzigailuaren hobespenak",
"preferences_autoplay_label": "Automatikoki erreproduzitu: ",
"preferences_continue_autoplay_label": "Erreproduzitu automatikoki hurrengo bideoa: ",
"preferences_quality_label": "Hobetsitako bideoaren kalitatea: ",
"preferences_volume_label": "Erreproduzigailuaren bolumena: ",
"preferences_comments_label": "Lehenetsitako iruzkinak: ",
"youtube": "YouTube",
"reddit": "Reddit",
"preferences_captions_label": "Lehenetsitako azpitituluak: ",
"preferences_related_videos_label": "Erakutsi erlazionatutako bideoak: ",
"preferences_annotations_label": "Erakutsi oharrak modu lehenetsian: ",
"preferences_category_visual": "Hobespen bisualak",
"preferences_player_style_label": "Erreproduzigailu mota: ",
"Player preferences": "Erreproduzigailuaren hobespenak",
"Always loop: ": "",
"Autoplay: ": "Automatikoki erreproduzitu: ",
"Play next by default: ": "",
"Autoplay next video: ": "Erreproduzitu automatikoki hurrengo bideoa: ",
"Listen by default: ": "",
"Proxy videos: ": "",
"Default speed: ": "",
"Preferred video quality: ": "Hobetsitako bideoaren kalitatea: ",
"Player volume: ": "Erreproduzigailuaren bolumena: ",
"Default comments: ": "Lehenetsitako iruzkinak: ",
"youtube": "youtube",
"reddit": "reddit",
"Default captions: ": "Lehenetsitako azpitituluak: ",
"Fallback captions: ": "",
"Show related videos: ": "Erakutsi erlazionatutako bideoak: ",
"Show annotations by default: ": "Erakutsi oharrak modu lehenetsian: ",
"Visual preferences": "Hobespen bisualak",
"Player style: ": "Erreproduzigailu mota: ",
"Dark mode: ": "Gai iluna: ",
"preferences_dark_mode_label": "Gaia: ",
"Theme: ": "Gaia: ",
"dark": "iluna",
"light": "argia",
"generic_subscriptions_count": "{{count}} harpidetza",
"generic_subscriptions_count_plural": "{{count}} harpidetzak",
"tokens_count": "{{count}} tokena",
"tokens_count_plural": "{{count}} tokenak",
"comments_points_count": "{{count}} puntua",
"comments_points_count_plural": "{{count}} puntuak",
"View more comments on Reddit": "Iruzkin gehiago Redditen",
"Fallback captions: ": "Ordezko azpitituluak: ",
"generic_subscribers_count": "{{count}} harpidedun",
"generic_subscribers_count_plural": "{{count}} harpidedunak",
"preferences_quality_option_dash": "DASH (kalitate egokitua)",
"preferences_listen_label": "Lehenetsiz jo: ",
"preferences_speed_label": "Abiadura lehenetsia: ",
"preferences_quality_dash_option_2160p": "2160p",
"preferences_quality_dash_option_144p": "144p",
"preferences_quality_dash_option_auto": "Auto",
"preferences_quality_dash_option_worst": "Txarrena",
"preferences_quality_dash_option_best": "Hoberena",
"preferences_quality_dash_option_4320p": "4320p",
"preferences_quality_dash_option_480p": "480p",
"preferences_quality_dash_option_240p": "240p",
"preferences_extend_desc_label": "Bideoaren azalpena automatikoki zabaldu: ",
"preferences_annotations_subscribed_label": "Harpidetutako kanalen oharrak erakutsi lehenetsiz? ",
"Redirect homepage to feed: ": "Hasierako orrira bidali jarraitzeko: ",
"channel name - reverse": "kanalaren izena - alderantziz",
"preferences_notifications_only_label": "Jakinarazpenak soilik erakutsi (baldin badago): ",
"Top enabled: ": "Goikoa gaitu: ",
"Import/export data": "Inportatu/exportatu data",
"Create playlist": "Zerrenda sortu",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Aditu! JavaScript itzalita dakazula ematen du. Hemen sakatu iruzkinak ikusteko. Denbora luza leikeela kontuan hartu.",
"Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "Ezinezkoa izena eman. Ziurtatu berresteko bi faktoreak (Authenticator edo SMS) piztuta daudela.",
"generic_views_count": "{{count}}ikusia",
"generic_views_count_plural": "{{count}}ikusiak",
"generic_playlists_count": "{{count}}zerrenda",
"generic_playlists_count_plural": "{{count}}zerrendak",
"Could not fetch comments": "Iruzkinei ezin heldu",
"Erroneous token": "Token okerra",
"Albanian": "Albaniarra",
"Azerbaijani": "Azerbaitarra",
"No such user": "Ez dago erabiltzailerik",
"Bulgarian": "Bulgariarra",
"Filipino": "Filipinera",
"French": "Frantsesa",
"French (auto-generated)": "Frantsesa (auto-sortua)",
"Show more": "Erakutsi gehiago",
"Show less": "Erakutsi gutxiago",
"Delete playlist": "Zerrenda ezabatu",
"Delete account": "Kontua ezabatu",
"User ID is a required field": "Erabiltzailearen IDa beharrezkoa da",
"English (United Kingdom)": "Ingelesa (Britania Handia",
"preferences_vr_mode_label": "360 graduko bideo interaktiboak (WebGL beharko): ",
"English (United States)": "Estatu batuarra (AEB)",
"English (auto-generated)": "Ingelesa (autosortua)",
"Arabic": "Arabiarra",
"Armenian": "Armeniarra",
"Bangla": "Banglera",
"Belarusian": "Bielorrusiara",
"Burmese": "Burmesera",
"Chinese (Simplified)": "Txinera (sinplifikatua)",
"preferences_watch_history_label": "Baimendu historia ikusi ",
"generic_videos_count": "{{count}}bideo",
"generic_videos_count_plural": "{{count}}bideoak",
"View privacy policy.": "Pribatutasun politika ikusi.",
"Cantonese (Hong Kong)": "Kantoniera (Hong Kong)",
"subscriptions_unseen_notifs_count": "{{count}} ezikusitako oharra",
"subscriptions_unseen_notifs_count_plural": "{{count}} ezikusitako oharrak",
"Trending": "Joera",
"Playlist privacy": "Zerrendaren privatutasuna",
"Switch Invidious Instance": "Invidious adibidea aldatu",
"Genre: ": "Genero: ",
"License: ": "Lizentzia: ",
"Family friendly? ": "Adeikorra familiarekin? ",
"Wilson score: ": "Wilsonen puntuazioa: ",
"Quota exceeded, try again in a few hours": "Kuota gaindituta, ordu batzuren bueltan berriro saiatu",
"comments_view_x_replies": "{{count}} erantzuna ikusi",
"comments_view_x_replies_plural": "{{count}} erantzunak ikusi",
"Catalan": "Katalaniera",
"Chinese": "Txinera",
"Chinese (China)": "Txinatarra",
"Chinese (Hong Kong)": "Hongkondarra",
"Chinese (Taiwan)": "Taiwandarra",
"Corsican": "Korsikera",
"Dutch (auto-generated)": "Alemaniera (auto-sortua)",
"Estonian": "Estoniera",
"Finnish": "Finlandiera",
"Galician": "Galizera",
"German (auto-generated)": "Alemaiera (auto-sortua)",
"Greek": "Greziera",
"crash_page_report_issue": "Aurreko ezerk ez badizu lagundu, arren <a href=\"`x`\"> GitHuben gai berri bat zabaldu </a> (ingelesez ahal bada) eta zure mezuan hurrengo testua sartu (testuari EZ itzulpena egin):",
"crash_page_search_issue": "GitHuben dauden gaiak <a href=\"`x`\"> buruz</a>",
"preferences_quality_option_medium": "Erdixka",
"preferences_quality_option_small": "Txikia",
"preferences_quality_dash_label": "DASH bideo kalitate lehenetsia: ",
"preferences_quality_dash_option_1440p": "1440p",
"preferences_quality_dash_option_1080p": "1080p",
"preferences_quality_dash_option_720p": "720p",
"preferences_quality_option_hd720": "HD720",
"preferences_quality_dash_option_360p": "360p",
"invidious": "Invidious",
"Source available here.": "Iturburua hemen eskura.",
"View JavaScript license information.": "JavaScriptaren lizentzi adierazpena ikusi.",
"Blacklisted regions: ": "zerrenda beltzaren zonaldeak: ",
"Premieres `x`": "'x' estrenaldiak",
"Wrong answer": "Erantzun ez zuzena",
"Password is a required field": "Pasahitza beharrezkoa da",
"Wrong username or password": "Pasahitza edo ezizena gaizki",
"Password cannot be longer than 55 characters": "Pasahitza 55 karaktere baino luzeagoa ezin da izan",
"This channel does not exist.": "Kanal hau ez dago.",
"`x` ago": "duela 'x'",
"Czech": "Txekiera",
"preferences_region_label": "Herrialdeko edukiera: ",
"preferences_sort_label": "Bideoak ordenatu: ",
"published": "argitaratuta",
"Only show latest video from channel: ": "Kanalaren azken bideoa soilik erakutsi ",
"preferences_category_admin": "Administratzailearen lehentasunak",
"Registration enabled: ": "Harpidetza gaituta: ",
"Save preferences": "Baloreak gorde",
"Token manager": "Token kudeatzailea",
"unsubscribe": "Baja eman",
"search": "Bilatu",
"Log out": "Irten",
"English": "Ingelesa",
"Afrikaans": "Afrikarra",
"Amharic": "Amharerra",
"Basque": "Euskera",
"Bosnian": "Bosniarra",
"Cebuano": "Zebuera",
"Chinese (Traditional)": "Txinera (Tradizionala)",
"Croatian": "Croaziera",
"Danish": "Daniera",
"Dutch": "Alemaniera",
"Esperanto": "Esperanto",
"Erroneous challenge": "Erronka okerra",
"View all playlists": "Zerrenda guztiak ikusi",
"Show annotations": "Oharrak erakutsi",
"Empty playlist": "Zerrenda hutsik",
"Please log in": "Sartu, mesedez",
"CAPTCHA is a required field": "CAPTCHA beharrezko eremua da",
"preferences_category_data": "Dataren lehentasunak",
"preferences_default_home_label": "Homepage lehenetsia: ",
"preferences_automatic_instance_redirect_label": "berbideratze adibide automatikoa (atzera egin berbideratzeko: invidious.io) ",
"Please sign in using 'Log in with Google'": "'Log in Googlerekin' erabili",
"`x` uploaded a video": "' x'(e)k bideo bat igo du",
"published - reverse": "argitaratuta - alderantziz",
"Could not get channel info.": "Kanalaren adierazpena ezin lortu.",
"alphabetically - reverse": "alfabetikoki - alderantziz",
"Public": "Orokorra",
"Unlisted": "Ez zerrendatua",
"Subscription manager": "Harpidetzen kudeatzailea",
"Updated `x` ago": "Duela 'x' eguneratua",
"Hide replies": "Erantzunak izkutatu",
"preferences_thin_mode_label": "Urri eran: ",
"Show replies": "Erantzunak erakutsi",
"Watch on YouTube": "YouTuben ikusi",
"Premieres in `x`": "'x'eko estrenaldiak",
"Delete playlist `x`?": "'x' zerrenda ezabatu nahi?",
"Token is expired, please try again": "Token kadukatua, saiatu berriro",
"Invalid TFA code": "TFA kodea ez da zuzena",
"CAPTCHA enabled: ": "CAPTCHA gaitu: ",
"Released under the AGPLv3 on Github.": "GitHubeko AGPLv3pean argitaratuta.",
"channel:`x`": "Kanal: 'x'",
"Georgian": "Georgiera",
"Incorrect password": "Pasahitza gaizki",
"Playlist does not exist.": "Zerrenda ez da existitzen.",
"preferences_category_misc": "Askotariko lehentasunak",
"View `x` comments": {
"([^.,0-9]|^)1([^.,0-9]|$)": "'x' iruzkina ikusi",
"": "'x' iruzkinak ikusi"
},
"Report statistics: ": "Estatistikak adierazi: ",
"preferences_max_results_label": "Jotzeko bideo zerrendaren luzera: ",
"Subscriptions": "Harpidetzak",
"Load more": "Gehiago atera",
"Change password": "Pasahitza aldatu",
"preferences_show_nick_label": "Erakutsi ezizena goian: ",
"View Reddit comments": "Redditeko iruzkinak ikusi",
"preferences_category_subscription": "Harpidetzaren lehentasunak",
"Hidden field \"challenge\" is a required field": "\"challenge\" eremu ezkutua beharrezkoa da",
"German": "Alemaniarra",
"Login failed. This may be because two-factor authentication is not turned on for your account.": "Ezin izena eman. Izan leike zure konturako berresteko bi faktoreak piztuta ez daudela.",
"View YouTube comments": "YouTubeko iruzkinak ikusi",
"Google verification code": "Googleren berresteko kodea",
"`x` is live": "'x' bizirik darrai",
"Password cannot be empty": "Pasahitza ezin da hutsik utzi",
"preferences_video_loop_label": "Beti begiztatu: ",
"Only show latest unwatched video from channel: ": "kanalaren azken bideo ezikusia erakutsi soilik ",
"Enable web notifications": "Webaren jakinarazpenak baimendu",
"revoke": "ukatu",
"preferences_continue_label": "Hurrengo lehenetsia jo: ",
"Whitelisted regions: ": "Zuri zerrendaren zonaldeak: ",
"Erroneous CAPTCHA": "CAPTCHA gaizki",
"Deleted or invalid channel": "Ezgai edota ezabatutako kanala",
"Could not create mix.": "Nahastea ezin sortu.",
"Not a playlist.": "Ez da zerrenda.",
"Hidden field \"token\" is a required field": "\"token\" eremu ezkutua beharrezkoa da",
"Import/export": "Inportatu/esportatu",
"alphabetically": "alfabetikoki",
"preferences_unseen_only_label": "Ezikusiak besterik ez erakutsi: ",
"Clear watch history": "Historia ezabatu",
"Manage subscriptions": "Harpidetzak kudeatu",
"Manage tokens": "Fitxak kudeatu",
"Watch history": "Historia ikusi",
"Login enabled: ": "Login gaitu: ",
"Hide annotations": "Oharrak izkutatu",
"Title": "Titulua",
"channel name": "Kanalaren izena",
"Authorize token for `x`?": "Baimendu tokena 'x'tzako?",
"Private": "Pribatua",
"Editing playlist `x`": "'x' zerrenda editatu",
"Could not pull trending pages.": "Ezin ekarri orri arrakastatsuak.",
"crash_page_read_the_faq": "Bide <a href=\"`x`\"> (FAQ) ohiko galderak</a>"
}
"Thin mode: ": "",
"Subscription preferences": "Harpidetzen hobespenak",
"Show annotations by default for subscribed channels: ": "",
"Redirect homepage to feed: ": "",
"Number of videos shown in feed: ": "",
"Sort videos by: ": "",
"published": "",
"published - reverse": "",
"alphabetically": "",
"alphabetically - reverse": "",
"channel name": "",
"channel name - reverse": "",
"Only show latest video from channel: ": "",
"Only show latest unwatched video from channel: ": "",
"Only show unwatched: ": "",
"Only show notifications (if there are any): ": "",
"Enable web notifications": "",
"`x` uploaded a video": "",
"`x` is live": "",
"Data preferences": "",
"Clear watch history": "",
"Import/export data": "",
"Change password": "",
"Manage subscriptions": "",
"Manage tokens": "",
"Watch history": "",
"Delete account": "",
"Administrator preferences": "",
"Default homepage: ": "",
"Feed menu: ": "",
"Top enabled: ": "",
"CAPTCHA enabled: ": "",
"Login enabled: ": "",
"Registration enabled: ": "",
"Report statistics: ": "",
"Save preferences": "",
"Subscription manager": "",
"Token manager": "",
"Token": "",
"`x` subscriptions": "",
"`x` tokens": "",
"Import/export": "",
"unsubscribe": "",
"revoke": "",
"Subscriptions": "",
"`x` unseen notifications": "",
"search": "",
"Log out": "",
"Released under the AGPLv3 by Omar Roth.": "",
"Source available here.": "",
"View JavaScript license information.": "",
"View privacy policy.": "",
"Trending": "",
"Public": "",
"Unlisted": "",
"Private": "",
"View all playlists": "",
"Updated `x` ago": "",
"Delete playlist `x`?": "",
"Delete playlist": "",
"Create playlist": "",
"Title": "",
"Playlist privacy": "",
"Editing playlist `x`": "",
"Watch on YouTube": "",
"Hide annotations": "",
"Show annotations": "",
"Genre: ": "",
"License: ": "",
"Family friendly? ": "",
"Wilson score: ": "",
"Engagement: ": "",
"Whitelisted regions: ": "",
"Blacklisted regions: ": "",
"Shared `x`": "",
"`x` views": "",
"Premieres in `x`": "",
"Premieres `x`": "",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "",
"View YouTube comments": "",
"View more comments on Reddit": "",
"View `x` comments": "",
"View Reddit comments": "",
"Hide replies": "",
"Show replies": "",
"Incorrect password": "",
"Quota exceeded, try again in a few hours": "",
"Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "",
"Invalid TFA code": "",
"Login failed. This may be because two-factor authentication is not turned on for your account.": "",
"Wrong answer": "",
"Erroneous CAPTCHA": "",
"CAPTCHA is a required field": "",
"User ID is a required field": "",
"Password is a required field": "",
"Wrong username or password": "",
"Please sign in using 'Log in with Google'": "",
"Password cannot be empty": "",
"Password cannot be longer than 55 characters": "",
"Please log in": "",
"Invidious Private Feed for `x`": "",
"channel:`x`": "",
"Deleted or invalid channel": "",
"This channel does not exist.": "",
"Could not get channel info.": "",
"Could not fetch comments": "",
"View `x` replies": "",
"`x` ago": "",
"Load more": "",
"`x` points": "",
"Could not create mix.": "",
"Empty playlist": "",
"Not a playlist.": "",
"Playlist does not exist.": "",
"Could not pull trending pages.": "",
"Hidden field \"challenge\" is a required field": "",
"Hidden field \"token\" is a required field": "",
"Erroneous challenge": "",
"Erroneous token": "",
"No such user": "",
"Token is expired, please try again": "",
"English": "",
"English (auto-generated)": "",
"Afrikaans": "",
"Albanian": "",
"Amharic": "",
"Arabic": "",
"Armenian": "",
"Azerbaijani": "",
"Bangla": "",
"Basque": "",
"Belarusian": "",
"Bosnian": "",
"Bulgarian": "",
"Burmese": "",
"Catalan": "",
"Cebuano": "",
"Chinese (Simplified)": "",
"Chinese (Traditional)": "",
"Corsican": "",
"Croatian": "",
"Czech": "",
"Danish": "",
"Dutch": "",
"Esperanto": "",
"Estonian": "",
"Filipino": "",
"Finnish": "",
"French": "",
"Galician": "",
"Georgian": "",
"German": "",
"Greek": "",
"Gujarati": "",
"Haitian Creole": "",
"Hausa": "",
"Hawaiian": "",
"Hebrew": "",
"Hindi": "",
"Hmong": "",
"Hungarian": "",
"Icelandic": "",
"Igbo": "",
"Indonesian": "",
"Irish": "",
"Italian": "",
"Japanese": "",
"Javanese": "",
"Kannada": "",
"Kazakh": "",
"Khmer": "",
"Korean": "",
"Kurdish": "",
"Kyrgyz": "",
"Lao": "",
"Latin": "",
"Latvian": "",
"Lithuanian": "",
"Luxembourgish": "",
"Macedonian": "",
"Malagasy": "",
"Malay": "",
"Malayalam": "",
"Maltese": "",
"Maori": "",
"Marathi": "",
"Mongolian": "",
"Nepali": "",
"Norwegian Bokmål": "",
"Nyanja": "",
"Pashto": "",
"Persian": "",
"Polish": "",
"Portuguese": "",
"Punjabi": "",
"Romanian": "",
"Russian": "",
"Samoan": "",
"Scottish Gaelic": "",
"Serbian": "",
"Shona": "",
"Sindhi": "",
"Sinhala": "",
"Slovak": "",
"Slovenian": "",
"Somali": "",
"Southern Sotho": "",
"Spanish": "",
"Spanish (Latin America)": "",
"Sundanese": "",
"Swahili": "",
"Swedish": "",
"Tajik": "",
"Tamil": "",
"Telugu": "",
"Thai": "",
"Turkish": "",
"Ukrainian": "",
"Urdu": "",
"Uzbek": "",
"Vietnamese": "",
"Welsh": "",
"Western Frisian": "",
"Xhosa": "",
"Yiddish": "",
"Yoruba": "",
"Zulu": "",
"`x` years": "",
"`x` months": "",
"`x` weeks": "",
"`x` days": "",
"`x` hours": "",
"`x` minutes": "",
"`x` seconds": "",
"Fallback comments: ": "",
"Popular": "",
"Top": "",
"About": "",
"Rating: ": "",
"Language: ": "",
"View as playlist": "",
"Default": "",
"Music": "",
"Gaming": "",
"News": "",
"Movies": "",
"Download": "",
"Download as: ": "",
"%A %B %-d, %Y": "",
"(edited)": "",
"YouTube comment permalink": "",
"permalink": "",
"`x` marked it with a ❤": "",
"Audio mode": "",
"Video mode": "",
"Videos": "",
"Playlists": "",
"Community": "",
"Current version: ": ""
}

View File

@ -1,415 +0,0 @@
{
"generic_views_count_0": "{{count}} بازدید",
"generic_videos_count_0": "{{count}} ویدئو",
"generic_playlists_count_0": "{{count}} فهرست پخش",
"generic_subscribers_count_0": "{{count}} دنبال کننده",
"generic_subscriptions_count_0": "{{count}} اشتراک ها",
"LIVE": "زنده",
"Shared `x` ago": "`x` پیش به اشتراک گذاشته شده",
"Unsubscribe": "لغو اشتراک",
"Subscribe": "مشترک شدن",
"View channel on YouTube": "دیدن کانال در یوتیوب",
"View playlist on YouTube": "دیدن فهرست پخش در یوتیوب",
"newest": "تازه‌ترین",
"oldest": "کهنه‌ترین",
"popular": "محبوب",
"last": "آخرین",
"Next page": "صفحه بعد",
"Previous page": "صفحه قبل",
"Clear watch history?": "پاک کردن تاریخچه نمایش؟",
"New password": "گذرواژه تازه",
"New passwords must match": "گذارواژه های تازه باید باهم همخوانی داشته باشند",
"Cannot change password for Google accounts": "نمیتوان گذرواژه را برای حساب های کاربری گوگل تغییر داد",
"Authorize token?": "توکن دسترسی؟",
"Authorize token for `x`?": "توکن دسترسی برای `x`؟",
"Yes": "بله",
"No": "خیر",
"Import and Export Data": "درون‌برد و برون‌برد داده",
"Import": "درون‌برد",
"Import Invidious data": "درون‌برد داده اینویدیوس",
"Import YouTube subscriptions": "درون‌برد اشتراک‌های یوتیوب",
"Import FreeTube subscriptions (.db)": "درون‌برد اشتراک‌های فری‌تیوب (.db)",
"Import NewPipe subscriptions (.json)": "درون‌برد اشتراک‌های نیوپایپ (.json)",
"Import NewPipe data (.zip)": "درون‌برد داده نیوپایپ (.zip)",
"Export": "برون‌برد",
"Export subscriptions as OPML": "برون‌برد اشتراک‌ها در قالب OPML",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "برون‌برد اشتراک‌ها در قالب OPML (برای نیوپایپ و فری‌تیوب)",
"Export data as JSON": "برون‌برد داده در قالب JSON",
"Delete account?": "حذف حساب کاربری؟",
"History": "تاریخچه",
"An alternative front-end to YouTube": "یک پیشانه جایگزین برای یوتیوب",
"JavaScript license information": "اطلاعات پروانه جاوااسکریپت",
"source": "منبع",
"Log in": "ورود",
"Log in/register": "ورود/ثبت نام",
"Log in with Google": "ورود با گوگل",
"User ID": "شناسه کاربری",
"Password": "گذرواژه",
"Time (h:mm:ss):": "زمان (h:mm:ss):",
"Text CAPTCHA": "کپچای متنی",
"Image CAPTCHA": "کپچای تصویری",
"Sign In": "ورود",
"Register": "ثبت نام",
"E-mail": "ایمیل",
"Google verification code": "کد تایید گوگل",
"Preferences": "ترجیحات",
"preferences_category_player": "ترجیحات نمایش‌دهنده",
"preferences_video_loop_label": "همواره ویدئو را بازپخش کن ",
"preferences_autoplay_label": "نمایش خودکار: ",
"preferences_continue_label": "پخش بعدی به طور پیشفرض: ",
"preferences_continue_autoplay_label": "پخش خودکار ویدیو بعدی: ",
"preferences_listen_label": "گوش کردن به طور پیشفرض: ",
"preferences_local_label": "پروکسی ویدیو ها: ",
"preferences_speed_label": "سرعت پیشفرض: ",
"preferences_quality_label": "کیفیت ویدیوی ترجیحی: ",
"preferences_volume_label": "صدای پخش کننده: ",
"preferences_comments_label": "نظرات پیشفرض: ",
"youtube": "یوتیوب",
"reddit": "ردیت",
"preferences_captions_label": "زیرنویس های پیشفرض: ",
"Fallback captions: ": "عقب گرد زیرنویس ها: ",
"preferences_related_videos_label": "نمایش ویدیو های مرتبط: ",
"preferences_annotations_label": "نمایش حاشیه نویسی ها به طور پیشفرض: ",
"preferences_extend_desc_label": "گسترش خودکار توضیحات ویدئو: ",
"preferences_vr_mode_label": "ویدئوها ۳۶۰ درجه تعاملی: ",
"preferences_category_visual": "ترجیحات بصری",
"preferences_player_style_label": "حالت پخش کننده: ",
"Dark mode: ": "حالت تاریک: ",
"preferences_dark_mode_label": "تم: ",
"dark": "تاریک",
"light": "روشن",
"preferences_thin_mode_label": "حالت نازک: ",
"preferences_category_misc": "ترجیحات متفرقه",
"preferences_automatic_instance_redirect_label": "هدایت خودکار نمونه (به طور پیش‌فرض به redirect.invidious.io): ",
"preferences_category_subscription": "ترجیحات اشتراک",
"preferences_annotations_subscribed_label": "نمایش حاشیه نویسی ها به طور پیشفرض برای کانال های مشترک شده: ",
"Redirect homepage to feed: ": "تغییر مسیر صفحه خانه به خوراک: ",
"preferences_max_results_label": "تعداد ویدیو های نمایش داده شده در خوراک: ",
"preferences_sort_label": "مرتب سازی ویدیو ها بر اساس: ",
"published": "منتشر شده",
"published - reverse": "منتشر شده - معکوس",
"alphabetically": "بر اساس حروف الفبا",
"alphabetically - reverse": "بر اساس حروف الفبا - معکوس",
"channel name": "نام کانال",
"channel name - reverse": "نام کانال - معکوس",
"Only show latest video from channel: ": "تنها نمایش آخرین ویدیو های کانال: ",
"Only show latest unwatched video from channel: ": "تنها نمایش آخرین ویدیو های تماشا نشده از کانال: ",
"preferences_unseen_only_label": "تنها نمایش ویدیو های تماشا نشده: ",
"preferences_notifications_only_label": "تنها نمایش اعلان ها (اگر وجود داشته باشد) ",
"Enable web notifications": "فعال کردن اعلان های وب",
"`x` uploaded a video": "`x` یک ویدیو بارگذاری کرد",
"`x` is live": "`x` زنده است",
"preferences_category_data": "ترجیحات داده",
"Clear watch history": "پاک‌کردن تاریخچه تماشا",
"Import/export data": "وارد کردن/خارج کردن داده",
"Change password": "تغییر گذرواژه",
"Manage subscriptions": "مدیریت اشتراک ها",
"Manage tokens": "مدیریت توکن ها",
"Watch history": "تاریخچه تماشا",
"Delete account": "حذف حساب کاربری",
"preferences_category_admin": "ترجیحات مدیریت",
"preferences_default_home_label": "صفحه خانه پیشفرض ",
"preferences_feed_menu_label": "منو خوراک: ",
"preferences_show_nick_label": "نمایش نام مستعار در بالا: ",
"Top enabled: ": "بالا فعال شده: ",
"CAPTCHA enabled: ": "CAPTCHA فعال شده: ",
"Login enabled: ": "ورود فعال شده: ",
"Registration enabled: ": "ثبت نام فعال شده: ",
"Report statistics: ": "گذارش آمار: ",
"Save preferences": "ذخیره ترجیحات",
"Subscription manager": "مدیریت اشتراک",
"Token manager": "مدیر توکن",
"Token": "توکن",
"tokens_count_0": "{{count}} توکن ها",
"Import/export": "وارد کردن/خارج کردن",
"unsubscribe": "لغو اشتراک",
"revoke": "ابطال",
"Subscriptions": "اشتراک ها",
"subscriptions_unseen_notifs_count_0": "{{count}} اعلان نادیده",
"search": "جستجو",
"Log out": "خروج",
"Released under the AGPLv3 on Github.": "منتشر شده تحت پروانه AGPLv3 روی گیت‌هاب.",
"Source available here.": "منبع اینجا دردسترس است.",
"View JavaScript license information.": "نمایش اطلاعات مجوز جاوا اسکریپت.",
"View privacy policy.": "نمایش سیاست حفظ حریم خصوصی.",
"Trending": "روند",
"Public": "عمومی",
"Unlisted": "لیست نشده",
"Private": "خصوصی",
"View all playlists": "نمایش همه سیاهه‌های پخش",
"Updated `x` ago": "بروز شده `x` پیش",
"Delete playlist `x`?": "حذف سیاههٔ پخش `x`؟",
"Delete playlist": "حذف سیاههٔ پخش",
"Create playlist": "ایجاد سیاههٔ پخش",
"Title": "عنوان",
"Playlist privacy": "حریم خصوصی سیاههٔ پخش",
"Editing playlist `x`": "تغییر سیاههٔ پخش `x`",
"Show more": "نمایش بیش‌تر",
"Show less": "نمایش کم‌تر",
"Watch on YouTube": "تماشا در یوتیوب",
"Switch Invidious Instance": "تعویض نمونه اینویدیوس",
"Hide annotations": "مخفی کردن حاشیه نویسی ها",
"Show annotations": "نمایش حاشیه نویسی ها",
"Genre: ": "ژانر: ",
"License: ": "مجوز: ",
"Family friendly? ": "خانواده دوستانه؟ ",
"Wilson score: ": "امتیاز ویلسون: ",
"Engagement: ": "نامزدی: ",
"Whitelisted regions: ": "مناطق لیست سفید: ",
"Blacklisted regions: ": "مناطق لیست سیاه: ",
"Shared `x`": "به اشتراک گذاشته شده `x`",
"Premieres in `x`": "برای اولین بار در `x`",
"Premieres `x`": "برای اولین بار `x`",
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "سلام! مثل اینکه تو جاوا اسکریپت رو خاموش کرده ای. اینجا کلیک کن تا نظرات را ببینی، این رو یادت باشه که ممکنه بارگذاری اونها کمی طول بکشه.",
"View YouTube comments": "نمایش نظرات یوتیوب",
"View more comments on Reddit": "نمایش نظرات بیشتر در ردیت",
"View `x` comments": {
"([^.,0-9]|^)1([^.,0-9]|$)": "نمایش `x` نظرات",
"": "نمایش `x` نظرات"
},
"View Reddit comments": "نمایش نظرات ردیت",
"Hide replies": "مخفی کردن پاسخ ها",
"Show replies": "نمایش پاسخ ها",
"Incorrect password": "گذرواژه نا درست",
"Quota exceeded, try again in a few hours": "سهمیه بیشتر شده است، چند ساعت بعد دوباره تلاش کنید",
"Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "قادر به ورود نیستید، مطمئن شوید احراز تایید-دو‌مرحله (Authenticator یا پیام‌کوتاه) خاموش باشد.",
"Invalid TFA code": "کد TFA نادرست است",
"Login failed. This may be because two-factor authentication is not turned on for your account.": "ورود با خطا مواجه شد. این ممکن است به خاطر احراز تایید-دو‌مرحله باشد که برای حساب کاربری شما فعال نشده است.",
"Wrong answer": "پاسخ غلط",
"Erroneous CAPTCHA": "CAPTCHA نا درست",
"CAPTCHA is a required field": "CAPTCHA یک فیلد ضروری است",
"User ID is a required field": "شناسه کاربری یک فیلد ضروری است",
"Password is a required field": "گذرواژه یک فیلد ضروری است",
"Wrong username or password": "نام کاربری یا گذرواژه غلط است",
"Please sign in using 'Log in with Google'": "لطفا با استفاده از 'ورود توسط گوگل' وارد شوید",
"Password cannot be empty": "گذرواژه نمیتواند خالی باشد",
"Password cannot be longer than 55 characters": "گذر واژه نمیتواند از ۵۵ کاراکتر بیشتر باشد",
"Please log in": "لطفا وارد شوید",
"Invidious Private Feed for `x`": "خوراک خصوصی زشت برای `x`",
"channel:`x`": "کانال: `x`",
"Deleted or invalid channel": "کانال نا معتبر یا پاک شده است",
"This channel does not exist.": "این کانال وجود ندارد.",
"Could not get channel info.": "نمیتوان اطلاعات کانال را دریافت کرد.",
"Could not fetch comments": "نمیتوان نظرات را دریافت کرد",
"comments_view_x_replies_0": "نمایش {{count}} پاسخ ها",
"`x` ago": "`x` پیش",
"Load more": "بارگذاری بیشتر",
"comments_points_count_0": "{{count}} نقطه ها",
"Could not create mix.": "نمیتوان میکس ساخت.",
"Empty playlist": "سیاههٔ پخش خالی",
"Not a playlist.": "یک سیاههٔ پخش نیست.",
"Playlist does not exist.": "سیاههٔ پخش وجود ندارد.",
"Could not pull trending pages.": "نمیتوان صفحه های پر طرفدار را بکشد.",
"Hidden field \"challenge\" is a required field": "فیلد مخفی \"چالش\" یک فیلد ضروری است",
"Hidden field \"token\" is a required field": "فیلد مخفی \"توکن\" یک فیلد ضروری است",
"Erroneous challenge": "چالش غلط",
"Erroneous token": "توکن غلط",
"No such user": "چنین کاربری وجود ندارد",
"Token is expired, please try again": "توکن ضروری است، لطفا دوباره تلاش کنید",
"English": "انگلیسی",
"English (auto-generated)": "انگلیسی (خودکار-تولید‌شده)",
"Afrikaans": "آفریکانس",
"Albanian": "آلبانیایی",
"Amharic": "امهری",
"Arabic": "عربی",
"Armenian": "ارمنی",
"Azerbaijani": "آذربایجانی",
"Bangla": "بنگالی",
"Basque": "باسکی",
"Belarusian": "بلاروسی",
"Bosnian": "بوسنیایی",
"Bulgarian": "بلغاری",
"Burmese": "برمه‌ای",
"Catalan": "کاتالان",
"Cebuano": "سبوانو",
"Chinese (Simplified)": "چینی (ساده شده)",
"Chinese (Traditional)": "چینی (سنتی)",
"Corsican": "کرس",
"Croatian": "کرواسی",
"Czech": "چکی",
"Danish": "دانمارکی",
"Dutch": "هلندی",
"Esperanto": "اسپرانتو",
"Estonian": "استونیایی",
"Filipino": "فلیپینی",
"Finnish": "فنلاندی",
"French": "فرانسوی",
"Galician": "گالیسی",
"Georgian": "گرجی",
"German": "آلمانی",
"Greek": "یونانی",
"Gujarati": "گجراتی",
"Haitian Creole": "کریول آییسینی",
"Hausa": "هوسه",
"Hawaiian": "هاوائی",
"Hebrew": "عبری",
"Hindi": "هندی",
"Hmong": "همونگ",
"Hungarian": "مجاری",
"Icelandic": "ایسلندی",
"Igbo": "ایگبو",
"Indonesian": "اندونزیایی",
"Irish": "شلتا",
"Italian": "ایتالیایی",
"Japanese": "ژاپنی",
"Javanese": "جاوه‌ای",
"Kannada": "کانارا",
"Kazakh": "قزاقی",
"Khmer": "خمر",
"Korean": "کره‌ای",
"Kurdish": "کردی",
"Kyrgyz": "قرقیزی",
"Lao": "لائو",
"Latin": "لاتین",
"Latvian": "لتونیایی",
"Lithuanian": "لیتوانیایی",
"Luxembourgish": "لوکزامبورگی",
"Macedonian": "مقدونی",
"Malagasy": "مالاگاسی",
"Malay": "مالایی",
"Malayalam": "مالایالم",
"Maltese": "مالتی",
"Maori": "مائوری",
"Marathi": "مراتی",
"Mongolian": "مغولی",
"Nepali": "نپالی",
"Norwegian Bokmål": "بوکمل",
"Nyanja": "چوایی",
"Pashto": "پشتو",
"Persian": "فارسی",
"Polish": "لهستانی",
"Portuguese": "پرتغالی",
"Punjabi": "پنجابی",
"Romanian": "رومانیایی",
"Russian": "روسی",
"Samoan": "ساموآیی",
"Scottish Gaelic": "گیلیک اسکاتلندی",
"Serbian": "صربی",
"Shona": "شونا",
"Sindhi": "سندی",
"Sinhala": "سینهالی",
"Slovak": "اسلواکی",
"Slovenian": "اسلونیایی",
"Somali": "سومالیایی",
"Southern Sotho": "سوتو",
"Spanish": "اسپانیایی",
"Spanish (Latin America)": "اسپانیایی (آمریکای لاتین)",
"Sundanese": "سوندایی",
"Swahili": "سواحلی",
"Swedish": "سوئدی",
"Tajik": "تاجیک",
"Tamil": "تامیلی",
"Telugu": "تلوگو",
"Thai": "تای",
"Turkish": "ترکی",
"Ukrainian": "اوکراینی",
"Urdu": "اردو",
"Uzbek": "ازبکی",
"Vietnamese": "ویتنامی",
"Welsh": "ولزی",
"Western Frisian": "فریسی غربی",
"Xhosa": "خوسایی",
"Yiddish": "ییدیش",
"Yoruba": "یوروبایی",
"Zulu": "زولو",
"generic_count_years_0": "{{count}} سال",
"generic_count_months_0": "{{count}} ماه",
"generic_count_weeks_0": "{{count}} هفته",
"generic_count_days_0": "{{count}} روز",
"generic_count_hours_0": "{{count}} ساعت",
"generic_count_minutes_0": "{{count}} دقیقه",
"generic_count_seconds_0": "{{count}} ثانیه",
"Fallback comments: ": "نظرات عقب گرد: ",
"Popular": "محبوب",
"Search": "جستجو",
"Top": "بالا",
"About": "درباره",
"Rating: ": "رتبه دهی: ",
"preferences_locale_label": "زبان: ",
"View as playlist": "نمایش به عنوان سیاههٔ پخش",
"Default": "پیشفرض",
"Music": "موسیقی",
"Gaming": "بازی",
"News": "اخبار",
"Movies": "فیلم‌ها",
"Download": "بارگیری",
"Download as: ": "بارگیری به عنوان: ",
"%A %B %-d, %Y": "%A %B %-d، %Y",
"(edited)": "(ویرایش شده)",
"YouTube comment permalink": "پیوست ثابت نظرات یوتیوب",
"permalink": "پیوست ثابت",
"`x` marked it with a ❤": "`x` نشان گذاری شده با یک ❤",
"Audio mode": "حالت صدا",
"Video mode": "حالت ویدیو",
"Videos": "ویدیو ها",
"Playlists": "سیاهه‌های پخش",
"Community": "اجتماع",
"search_filters_sort_option_relevance": "مرتبط بودن",
"search_filters_sort_option_rating": "امتیاز",
"search_filters_sort_option_date": "تاریخ بارگذاری",
"search_filters_sort_option_views": "تعداد بازدید",
"search_filters_type_label": "نوع",
"search_filters_duration_label": "مدت",
"search_filters_features_label": "ویژگی‌ها",
"search_filters_sort_label": "به ترتیب",
"search_filters_date_option_hour": "یک ساعت گذشته",
"search_filters_date_option_today": "امروز",
"search_filters_date_option_week": "این هفته",
"search_filters_date_option_month": "این ماه",
"search_filters_date_option_year": "امسال",
"search_filters_type_option_video": "ویدئو",
"search_filters_type_option_channel": "کانال",
"search_filters_type_option_playlist": "سیاههٔ پخش",
"search_filters_type_option_movie": "فیلم",
"search_filters_type_option_show": "نمایش",
"search_filters_features_option_hd": "HD",
"search_filters_features_option_subtitles": "زیرنویس",
"search_filters_features_option_c_commons": "کریتیو کامونز",
"search_filters_features_option_three_d": "سه‌بعدی",
"search_filters_features_option_live": "زنده",
"search_filters_features_option_four_k": "4K",
"search_filters_features_option_location": "مکان",
"search_filters_features_option_hdr": "HDR",
"Current version: ": "نسخه فعلی: ",
"next_steps_error_message": "اکنون بایستی یکی از این موارد را امتحان کنید: ",
"next_steps_error_message_refresh": "تازه‌سازی",
"next_steps_error_message_go_to_youtube": "رفتن به یوتیوب",
"preferences_quality_option_hd720": "HD720",
"preferences_quality_option_dash": "DASH (کیفیت قابل تطبیق)",
"preferences_quality_option_medium": "میانه",
"preferences_quality_option_small": "پایین",
"preferences_quality_dash_option_auto": "خودکار",
"preferences_quality_dash_option_best": "بهترین",
"preferences_quality_dash_option_worst": "بدترین",
"preferences_quality_dash_option_4320p": "4320p",
"preferences_quality_dash_option_2160p": "2160p",
"preferences_quality_dash_option_1440p": "1440p",
"preferences_quality_dash_option_1080p": "1080p",
"preferences_quality_dash_option_720p": "720p",
"preferences_quality_dash_option_480p": "480p",
"preferences_quality_dash_option_360p": "360p",
"preferences_quality_dash_option_240p": "240p",
"preferences_quality_dash_option_144p": "144p",
"invidious": "اینویدیوس",
"search_filters_features_option_three_sixty": "360°",
"footer_donate_page": "کمک مالی",
"footer_source_code": "کد منبع",
"footer_modfied_source_code": "کد منبع ویرایش شده",
"none": "هیچ‌کدام",
"videoinfo_started_streaming_x_ago": "پخش جریانی `x` پیش آغاز شد",
"videoinfo_watch_on_youTube": "تماشا در یوتیوب",
"videoinfo_youTube_embed_link": "توکار",
"videoinfo_invidious_embed_link": "پیوند توکار",
"download_subtitles": "زیرنویس‌ها - `x` (.vtt)",
"Video unavailable": "ویدئو دردسترس نیست",
"preferences_save_player_pos_label": "ذخیره زمان کنونی ویدئو: ",
"search_filters_features_option_purchased": "خریداری شده",
"preferences_quality_dash_label": "کیفیت ترجیحی ویدئو DASH: ",
"preferences_region_label": "کشور محتوا: ",
"footer_documentation": "مستندات",
"footer_original_source_code": "کد منبع اصلی",
"search_filters_duration_option_long": "بلند (> 20 دقیقه)",
"adminprefs_modified_source_code_url_label": "URL مخزن کد منبع ویریش شده",
"search_filters_duration_option_short": "کوتاه (< 4 دقیقه)",
"search_filters_title": "پالایه"
}

Some files were not shown because too many files have changed in this diff Show More