Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
Omar Roth | 50bab26a3a | 5 years ago |
@ -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))
|
@ -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
|
@ -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 +0,0 @@
|
||||
custom: https://invidious.io/donate/
|
@ -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):
|
||||
-->
|
@ -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. -->
|
@ -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. -->
|
@ -1,37 +0,0 @@
|
||||
name: Close duplicates
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-latest
|
||||
permissions: write-all
|
||||
steps:
|
||||
- uses: iv-org/close-potential-duplicates@v1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Issue title filter work with anymatch https://www.npmjs.com/package/anymatch.
|
||||
# Any matched issue will stop detection immediately.
|
||||
# You can specify multi filters in each line.
|
||||
filter: ''
|
||||
# Exclude keywords in title before detecting.
|
||||
exclude: ''
|
||||
# Label to set, when potential duplicates are detected.
|
||||
label: duplicate
|
||||
# Get issues with state to compare. Supported state: 'all', 'closed', 'open'.
|
||||
state: open
|
||||
# If similarity is higher than this threshold([0,1]), issue will be marked as duplicate.
|
||||
threshold: 0.9
|
||||
# Reactions to be add to comment when potential duplicates are detected.
|
||||
# Available reactions: "-1", "+1", "confused", "laugh", "heart", "hooray", "rocket", "eyes"
|
||||
reactions: ''
|
||||
close: true
|
||||
# Comment to post when potential duplicates are detected.
|
||||
comment: |
|
||||
Hello, your issue is a duplicate of this/these issue(s): {{#issues}}
|
||||
- #{{ number }} [accuracy: {{ accuracy }}%]
|
||||
{{/issues}}
|
||||
|
||||
If this is a mistake please explain why and ping @\unixfox, @\SamantazFox and @\TheFrenchGhosty.
|
||||
|
||||
Please refrain from opening new issues, it won't help in solving your problem.
|
@ -1,128 +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.4.1
|
||||
- 1.5.1
|
||||
- 1.6.2
|
||||
- 1.7.3
|
||||
- 1.8.1
|
||||
include:
|
||||
- crystal: nightly
|
||||
stable: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install Crystal
|
||||
uses: crystal-lang/install-crystal@v1.7.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
|
||||
|
||||
|
@ -1,105 +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 without QUIC 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"
|
||||
"disable_quic=1"
|
||||
|
||||
- name: Build and push Docker ARM64 image without QUIC 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"
|
||||
"disable_quic=1"
|
||||
|
||||
- name: Build and push Docker AMD64 image with QUIC 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 }}-quic,quay.io/invidious/invidious:latest-quic
|
||||
build-args: release=1
|
||||
|
||||
- name: Build and push Docker ARM64 image with QUIC 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-quic,quay.io/invidious/invidious:latest-arm64-quic
|
||||
build-args: release=1
|
@ -1,26 +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
|
||||
# Never mark feature requests/enhancements as stale
|
||||
exempt-issue-labels: "feature-request,enhancement,exempt-stale"
|
@ -1,3 +0,0 @@
|
||||
[submodule "mocks"]
|
||||
path = mocks
|
||||
url = ../mocks
|
@ -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
|
@ -1,124 +0,0 @@
|
||||
# -----------------------
|
||||
# Compilation options
|
||||
# -----------------------
|
||||
|
||||
RELEASE := 1
|
||||
STATIC := 0
|
||||
|
||||
DISABLE_QUIC := 1
|
||||
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
|
||||
|
||||
ifeq ($(API_ONLY), 1)
|
||||
FLAGS += -Dapi_only
|
||||
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 " API_ONLY Build invidious without a GUI (Default: 0)"
|
||||
@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
|
@ -1,181 +1,255 @@
|
||||
<div align="center">
|
||||
<img src="assets/invidious-colored-vector.svg" width="192" height="192" alt="Invidious logo">
|
||||
<h1>Invidious</h1>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<h3>An open source alternative front-end to YouTube</h3>
|
||||
|
||||
<a href="https://invidious.io/">Website</a>
|
||||
•
|
||||
<a href="https://instances.invidious.io/">Instances list</a>
|
||||
•
|
||||
<a href="https://docs.invidious.io/faq/">FAQ</a>
|
||||
•
|
||||
<a href="https://docs.invidious.io/">Documentation</a>
|
||||
•
|
||||
<a href="#contribute">Contribute</a>
|
||||
•
|
||||
<a href="https://invidious.io/donate/">Donate</a>
|
||||
|
||||
<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
|
||||
|
||||
[![Build Status](https://travis-ci.org/omarroth/invidious.svg?branch=master)](https://travis-ci.org/omarroth/invidious)
|
||||
|
||||
## 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) |
|
||||
|
||||
## Invidious is an alternative front-end to YouTube
|
||||
|
||||
## Features
|
||||
|
||||
**User features**
|
||||
- Lightweight
|
||||
- Audio-only mode (and no need to keep window open on mobile)
|
||||
- [Free software](https://github.com/omarroth/invidious) (AGPLv3 licensed)
|
||||
- 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)
|
||||
|
||||
**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
|
||||
|
||||
**Technical features**
|
||||
- Embedded video support
|
||||
- [Developer API](https://docs.invidious.io/api/)
|
||||
- Does not use official YouTube APIs
|
||||
- No Contributor License Agreement (CLA)
|
||||
|
||||
|
||||
## Quick start
|
||||
|
||||
**Using invidious:**
|
||||
|
||||
- [Select a public instance from the list](https://instances.invidious.io) and start watching videos right now!
|
||||
|
||||
**Hosting invidious:**
|
||||
- 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)
|
||||
|
||||
Liberapay: https://liberapay.com/omarroth
|
||||
BTC: 356DpZyMXu6rYd55Yqzjs29n79kGKWcYrY
|
||||
BCH: qq4ptclkzej5eza6a50et5ggc58hxsq5aylqut2npk
|
||||
|
||||
## 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)
|
||||
|
||||
- [Follow the installation instructions](https://docs.invidious.io/installation/)
|
||||
## Screenshots
|
||||
|
||||
| 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
|
||||
|
||||
See [Invidious-Updater](https://github.com/tmiland/Invidious-Updater) for a self-contained script that can automatically install and update Invidious.
|
||||
|
||||
### Docker:
|
||||
|
||||
#### Build and start cluster:
|
||||
|
||||
```bash
|
||||
$ docker-compose up
|
||||
```
|
||||
|
||||
And visit `localhost:3000` in your browser.
|
||||
|
||||
#### Rebuild cluster:
|
||||
|
||||
```bash
|
||||
$ docker-compose build
|
||||
```
|
||||
|
||||
#### Delete data and rebuild:
|
||||
|
||||
```bash
|
||||
$ docker volume rm invidious_postgresdata
|
||||
$ docker-compose build
|
||||
```
|
||||
|
||||
### 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/
|
||||
|
||||
The documentation's source code is available in this repository:
|
||||
https://github.com/iv-org/documentation
|
||||
|
||||
### Extensions
|
||||
|
||||
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.
|
||||
|
||||
The documentation contains a list of browser extensions that we recommended to use along with Invidious.
|
||||
|
||||
You can read more here: https://docs.invidious.io/applications/
|
||||
|
||||
|
||||
## Contribute
|
||||
|
||||
### Code
|
||||
|
||||
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 ).
|
||||
[Documentation](https://github.com/omarroth/invidious/wiki) can be found in the wiki.
|
||||
|
||||
### Translations
|
||||
## Extensions
|
||||
|
||||
We use [Weblate](https://weblate.org) to manage Invidious translations.
|
||||
[Extensions](https://github.com/omarroth/invidious/wiki/Extensions) can be found in the wiki, as well as documentation for integrating it into other projects.
|
||||
|
||||
You can suggest new translations and/or correction here: https://hosted.weblate.org/engage/invidious/.
|
||||
## Made with 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, ...
|
||||
- [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.
|
||||
|
||||
## Contributing
|
||||
|
||||
## Projects using Invidious
|
||||
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
|
||||
|
||||
- [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_de_L/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-wa): Progressive Web App 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).
|
||||
- [Playlet](https://github.com/iBicha/playlet): Unofficial Youtube client for Roku TV.
|
||||
- [Clipious](https://github.com/lamarios/clipious): Unofficial Invidious client for Android.
|
||||
## Contact
|
||||
|
||||
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.
|
||||
|
||||
## Liability
|
||||
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.
|
||||
|
||||
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.
|
||||
## License
|
||||
|
||||
You may view the LICENSE in which this software is provided to you [here](./LICENSE).
|
||||
[![GNU AGPLv3 Image](https://www.gnu.org/graphics/agplv3-155x51.png)](http://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
|
||||
> 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.
|
||||
|
@ -1 +0,0 @@
|
||||
https://hosted.weblate.org/projects/invidious/
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -1,264 +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);
|
||||
}
|
||||
|
||||
/* Overlay */
|
||||
.video-js .vjs-overlay {
|
||||
background-color: rgba(35, 35, 35, 0.75) !important;
|
||||
}
|
||||
.video-js .vjs-overlay * {
|
||||
color: rgba(255, 255, 255, 1) !important;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -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}
|
@ -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}
|
@ -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)}
|
@ -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}
|
@ -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 |
@ -1,254 +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) {
|
||||
let storageItem = localStorage.getItem(key)
|
||||
if (!storageItem) return;
|
||||
try {
|
||||
return JSON.parse(decodeURIComponent(storageItem));
|
||||
} catch(e) {
|
||||
// Erase non parsable value
|
||||
helpers.storage.remove(key);
|
||||
}
|
||||
},
|
||||
set: function (key, value) {
|
||||
let encoded_value = encodeURIComponent(JSON.stringify(value))
|
||||
localStorage.setItem(key, encoded_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';
|
||||
}
|
||||
};
|
||||
})()
|
||||
};
|
@ -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;
|
File diff suppressed because one or more lines are too long
@ -1,46 +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';
|
||||
} else if (theme === THEME_LIGHT) {
|
||||
toggle_theme.children[0].className = 'icon ion-ios-moon';
|
||||
document.body.className = 'light-theme';
|
||||
} else {
|
||||
document.body.className = 'no-theme';
|
||||
window.addEventListener('storage', function (e) {
|
||||
if (e.key === 'dark_mode') {
|
||||
update_mode(e.newValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 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));
|
||||
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);
|
||||
});
|
||||
|
||||
// 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);
|
||||
|
||||
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].setAttribute('class', 'icon ion-ios-moon');
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -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});
|
@ -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});
|
File diff suppressed because one or more lines are too long
@ -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});
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,24 +0,0 @@
|
||||
'use strict';
|
||||
var save_player_pos_key = 'save_player_pos';
|
||||
|
||||
function get_all_video_times() {
|
||||
return helpers.storage.get(save_player_pos_key) || {};
|
||||
}
|
||||
|
||||
document.querySelectorAll('.watched-indicator').forEach(function (indicator) {
|
||||
var watched_part = get_all_video_times()[indicator.dataset.id];
|
||||
var total = parseInt(indicator.dataset.length, 10);
|
||||
if (watched_part === undefined) {
|
||||
watched_part = total;
|
||||
}
|
||||
var percentage = Math.round((watched_part / total) * 100);
|
||||
|
||||
if (percentage < 5) {
|
||||
percentage = 5;
|
||||
}
|
||||
if (percentage > 90) {
|
||||
percentage = 100;
|
||||
}
|
||||
|
||||
indicator.style.width = percentage + '%';
|
||||
});
|
@ -1,2 +1,3 @@
|
||||
User-agent: *
|
||||
Disallow: /
|
||||
Disallow: /search
|
||||
Disallow: /login
|
@ -1,4 +0,0 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
@ -1,926 +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.
|
||||
##
|
||||
## 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: [""]
|
||||
|
||||
##
|
||||
## Enable/Disable the user notifications for all users
|
||||
##
|
||||
## Note: On large instances, it is recommended to set this option to 'false'
|
||||
## in order to reduce the amount of data written to the database, and hence
|
||||
## improve the overall performance of the instance.
|
||||
##
|
||||
## Accepted values: true, false
|
||||
## Default: true
|
||||
##
|
||||
#enable_user_notifications: true
|
||||
|
||||
# -----------------------------
|
||||
# Background jobs
|
||||
# -----------------------------
|
||||
|
||||
##
|
||||
## Number of threads to use when crawling channel videos (during
|
||||
## subscriptions update).
|
||||
##
|
||||
## Notes: This setting is overridden if either "-c THREADS" or
|
||||
## "--channel-threads=THREADS" is 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: This setting is overridden if either "-f THREADS" or
|
||||
## "--feed-threads=THREADS" is 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
|
||||
|
||||
|
||||
jobs:
|
||||
|
||||
## Options for the database cleaning job
|
||||
clear_expired_items:
|
||||
|
||||
## Enable/Disable job
|
||||
##
|
||||
## Accepted values: true, false
|
||||
## Default: true
|
||||
##
|
||||
enable: true
|
||||
|
||||
## Options for the channels updater job
|
||||
refresh_channels:
|
||||
|
||||
## Enable/Disable job
|
||||
##
|
||||
## Accepted values: true, false
|
||||
## Default: true
|
||||
##
|
||||
enable: true
|
||||
|
||||
## Options for the RSS feeds updater job
|
||||
refresh_feeds:
|
||||
|
||||
## Enable/Disable job
|
||||
##
|
||||
## Accepted values: true, false
|
||||
## Default: true
|
||||
##
|
||||
enable: true
|
||||
|
||||
|
||||
# -----------------------------
|
||||
# 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: ""
|
||||
|
||||
##
|
||||
## Maximum custom playlist length limit.
|
||||
##
|
||||
## Accepted values: Integer
|
||||
## Default: 500
|
||||
##
|
||||
#playlist_length_limit: 500
|
||||
|
||||
#########################################
|
||||
#
|
||||
# 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: "dark", "light", "auto"
|
||||
## Default: "auto"
|
||||
##
|
||||
#dark_mode: "auto"
|
||||
|
||||
##
|
||||
## 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
|
||||
|
||||
##
|
||||
## Save the playback position
|
||||
## Allow to continue watching at the previous position when
|
||||
## watching the same video.
|
||||
##
|
||||
## Accepted values: true, false
|
||||
## Default: false
|
||||
##
|
||||
#save_player_pos: false
|
||||
|
||||
# -----------------------------
|
||||
# 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
|
@ -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:
|
@ -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;"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
@ -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;"
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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;"
|
||||
|
@ -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;"
|
||||
|
@ -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"
|
||||
|
@ -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;"
|
||||
|
@ -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'"
|
||||
|
@ -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" ]
|
@ -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
|
@ -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
|
@ -1,6 +1,6 @@
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
repository: https://charts.bitnami.com/bitnami/
|
||||
version: 12.1.9
|
||||
digest: sha256:71ff342a6c0a98bece3d7fe199983afb2113f8db65a3e3819de875af2c45add7
|
||||
generated: "2023-01-20T20:42:32.757707004Z"
|
||||
repository: https://kubernetes-charts.storage.googleapis.com/
|
||||
version: 8.3.0
|
||||
digest: sha256:1feec3c396cbf27573dc201831ccd3376a4a6b58b2e7618ce30a89b8f5d707fd
|
||||
generated: "2020-02-07T13:39:38.624846+01:00"
|
||||
|
@ -1 +0,0 @@
|
||||
{}
|
@ -1,94 +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": "নতুন পাসওয়ার্ড অবশ্যই মিলতে হবে",
|
||||
"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": "লগ ইন/রেজিস্টার",
|
||||
"User ID": "ইউজার আইডি",
|
||||
"Password": "পাসওয়ার্ড",
|
||||
"Time (h:mm:ss):": "সময় (ঘণ্টা:মিনিট:সেকেন্ড):",
|
||||
"Text CAPTCHA": "টেক্সট ক্যাপচা",
|
||||
"Image CAPTCHA": "চিত্র ক্যাপচা",
|
||||
"Sign In": "সাইন ইন",
|
||||
"Register": "নিবন্ধন",
|
||||
"E-mail": "ই-মেইল",
|
||||
"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": "৭২০পি"
|
||||
}
|
@ -1,58 +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": "নতুন পাসওয়ার্ড অবশ্যই মিলতে হবে",
|
||||
"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": "লগ ইন/রেজিস্টার",
|
||||
"User ID": "ইউজার আইডি",
|
||||
"Password": "পাসওয়ার্ড",
|
||||
"Time (h:mm:ss):": "সময় (ঘণ্টা:মিনিট:সেকেন্ড):",
|
||||
"Text CAPTCHA": "টেক্সট ক্যাপচা",
|
||||
"Image CAPTCHA": "চিত্র ক্যাপচা",
|
||||
"Sign In": "সাইন ইন",
|
||||
"Register": "নিবন্ধন",
|
||||
"E-mail": "ই-মেইল",
|
||||
"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": "প্লেয়ার শব্দের মাত্রা: "
|
||||
}
|
@ -1,479 +0,0 @@
|
||||
{
|
||||
"oldest": "més antic",
|
||||
"Yes": "Sí",
|
||||
"preferences_quality_label": "Qualitat de vídeo preferida: ",
|
||||
"newest": "més nou",
|
||||
"No": "No",
|
||||
"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: ",
|
||||
"channel_tab_videos_label": "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": "Cerca",
|
||||
"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": "Cerca",
|
||||
"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",
|
||||
"preferences_volume_label": "Volum del reproductor: ",
|
||||
"invidious": "Invidious",
|
||||
"preferences_quality_dash_option_144p": "144p",
|
||||
"Turkish (auto-generated)": "Turc (generat automàticament)",
|
||||
"Urdu": "Urdú",
|
||||
"Vietnamese (auto-generated)": "Vietnamita (generat automàticament)",
|
||||
"Welsh": "Gal·lès",
|
||||
"Yoruba": "Ioruba",
|
||||
"YouTube comment permalink": "Enllaç permanent de comentari de YouTube",
|
||||
"Channel Sponsor": "Patrocinador del canal",
|
||||
"Audio mode": "Mode d'àudio",
|
||||
"search_filters_date_option_none": "Qualsevol data",
|
||||
"search_filters_type_option_playlist": "Llista de reproducció",
|
||||
"search_filters_type_option_movie": "Pel·lícula",
|
||||
"search_filters_features_option_four_k": "4K",
|
||||
"search_filters_features_option_subtitles": "Subtítols/CC",
|
||||
"search_filters_features_option_live": "Directe",
|
||||
"search_filters_features_option_hd": "HD",
|
||||
"search_filters_features_option_hdr": "HDR",
|
||||
"search_filters_features_option_location": "Ubicació",
|
||||
"search_filters_apply_button": "Aplica els filtres seleccionats",
|
||||
"videoinfo_started_streaming_x_ago": "Ha començat el directe fa `x`",
|
||||
"next_steps_error_message_go_to_youtube": "Vés a YouTube",
|
||||
"footer_donate_page": "Feu un donatiu",
|
||||
"footer_original_source_code": "Codi font original",
|
||||
"videoinfo_watch_on_youTube": "Veure a YouTube",
|
||||
"user_saved_playlists": "`x` llistes de reproducció guardades",
|
||||
"adminprefs_modified_source_code_url_label": "URL al repositori de codi font modificat",
|
||||
"none": "cap",
|
||||
"footer_modfied_source_code": "Codi font modificat",
|
||||
"videoinfo_invidious_embed_link": "Incrusta l'enllaç",
|
||||
"download_subtitles": "Subtítols - `x` (.vtt)",
|
||||
"user_created_playlists": "`x`llistes de reproducció creades",
|
||||
"Video unavailable": "Vídeo no disponible",
|
||||
"channel_tab_channels_label": "Canals",
|
||||
"channel_tab_playlists_label": "Llistes de reproducció",
|
||||
"channel_tab_community_label": "Comunitat",
|
||||
"Czech": "Txec",
|
||||
"Default": "Per defecte",
|
||||
"Amharic": "Amàric",
|
||||
"preferences_automatic_instance_redirect_label": "Redirecció automàtica d'instàncies (retorna a redirect.invidious.io): ",
|
||||
"Login enabled: ": "Activa inici de sessió: ",
|
||||
"Registration enabled: ": "Activa registre: ",
|
||||
"Whitelisted regions: ": "Regions a la llista blanca: ",
|
||||
"Chinese (Simplified)": "Xinès (Simplificat)",
|
||||
"Corsican": "Cors",
|
||||
"Estonian": "Estonià",
|
||||
"Japanese (auto-generated)": "Japonès (generat automàticament)",
|
||||
"English (United States)": "Anglès (Estats Units)",
|
||||
"English (auto-generated)": "Anglès (generat automàticament)",
|
||||
"Cebuano": "Cebuà",
|
||||
"Esperanto": "Esperanto",
|
||||
"Scottish Gaelic": "Gaèlic escocès",
|
||||
"Playlists": "Llistes de reproducció",
|
||||
"search_filters_title": "Filtres",
|
||||
"search_filters_type_option_all": "Qualsevol tipus",
|
||||
"search_filters_duration_option_none": "Qualsevol duració",
|
||||
"next_steps_error_message": "Després d'això, hauríeu d'intentar: ",
|
||||
"next_steps_error_message_refresh": "Recarregar la pàgina",
|
||||
"crash_page_refresh": "ha intentat <a href=\"`x`\">actualitzar la pàgina</a>",
|
||||
"crash_page_report_issue": "Si cap de les anteriors no ha ajudat, <a href=\"`x`\">obre un nou issue a GitHub</a> (preferiblement en anglès) i inclou el text següent al missatge (NO tradueixis aquest text):",
|
||||
"generic_subscriptions_count": "{{count}} subscripció",
|
||||
"generic_subscriptions_count_plural": "{{count}} subscripcions",
|
||||
"error_video_not_in_playlist": "El vídeo sol·licitat no existeix en aquesta llista de reproducció. <a href=\"`x`\">Feu clic aquí per a la pàgina d'inici de la llista de reproducció.</a>",
|
||||
"comments_points_count": "{{count}} punt",
|
||||
"comments_points_count_plural": "{{count}} punts",
|
||||
"%A %B %-d, %Y": "%A %B %-d, %Y",
|
||||
"Create playlist": "Crear llista de reproducció",
|
||||
"Text CAPTCHA": "Text CAPTCHA",
|
||||
"Next page": "Pàgina següent",
|
||||
"preferences_category_visual": "Preferències visuals",
|
||||
"preferences_unseen_only_label": "Mostra només no vistos: ",
|
||||
"preferences_listen_label": "Escolta per defecte: ",
|
||||
"Import": "Importar",
|
||||
"Token": "Testimoni",
|
||||
"Wilson score: ": "Puntuació de Wilson: ",
|
||||
"search_filters_date_label": "Data de càrrega",
|
||||
"search_filters_features_option_three_sixty": "360°",
|
||||
"source": "font",
|
||||
"preferences_default_home_label": "Pàgina d'inici per defecte: ",
|
||||
"preferences_comments_label": "Comentaris per defecte: ",
|
||||
"`x` uploaded a video": "`x` ha penjat un vídeo",
|
||||
"Released under the AGPLv3 on Github.": "Publicat sota l'AGPLv3 a GitHub.",
|
||||
"Token manager": "Gestor de testimonis",
|
||||
"Watch history": "Historial de reproduccions",
|
||||
"Authorize token?": "Autoritzar testimoni?",
|
||||
"Source available here.": "Font disponible aquí.",
|
||||
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Exporta subscripcions com a OPML (per a NewPipe i FreeTube)",
|
||||
"Log in": "Inicia sessió",
|
||||
"search_filters_sort_option_date": "Data de càrrega",
|
||||
"Unlisted": "No llistat",
|
||||
"View privacy policy.": "Veure política de privadesa.",
|
||||
"Public": "Públic",
|
||||
"View all playlists": "Veure totes les llistes de reproducció",
|
||||
"reddit": "Reddit",
|
||||
"Manage tokens": "Gestiona testimonis",
|
||||
"Not a playlist.": "No és una llista de reproducció.",
|
||||
"preferences_local_label": "Vídeos de Proxy: ",
|
||||
"View channel on YouTube": "Veure canal a Youtube",
|
||||
"preferences_quality_dash_option_1080p": "1080p",
|
||||
"Top enabled: ": "Activa top: ",
|
||||
"Delete playlist `x`?": "Eliminar llista de reproducció `x`?",
|
||||
"View JavaScript license information.": "Consulta la informació de la llicència de JavaScript.",
|
||||
"Playlist privacy": "Privacitat de la llista de reproducció",
|
||||
"search_message_no_results": "No s'han trobat resultats.",
|
||||
"search_message_use_another_instance": " També es pot <a href=\"`x`\">buscar en una altra instància</a>.",
|
||||
"Genre: ": "Gènere: ",
|
||||
"Hidden field \"challenge\" is a required field": "El camp ocult \"repte\" és un camp obligatori",
|
||||
"Burmese": "Birmà",
|
||||
"View as playlist": "Mostra com a llista de reproducció",
|
||||
"preferences_category_subscription": "Preferències de subscripció",
|
||||
"Music in this video": "Música en aquest vídeo",
|
||||
"Artist: ": "Artista: ",
|
||||
"Album: ": "Àlbum: ",
|
||||
"Shared `x`": "Compartit `x`",
|
||||
"Premieres `x`": "Estrena `x`",
|
||||
"View more comments on Reddit": "Veure més comentaris a Reddit",
|
||||
"View `x` comments": {
|
||||
"([^.,0-9]|^)1([^.,0-9]|$)": "Veure `x` comentari",
|
||||
"": "Veure `x` comentaris"
|
||||
},
|
||||
"View Reddit comments": "Veure comentaris de Reddit",
|
||||
"Incorrect password": "Contrasenya incorrecta",
|
||||
"Erroneous CAPTCHA": "CAPTCHA erroni",
|
||||
"CAPTCHA is a required field": "El CAPTCHA és un camp obligatori",
|
||||
"Korean (auto-generated)": "Coreà (generat automàticament)",
|
||||
"Kyrgyz": "Kirguís",
|
||||
"Latin": "Llatí",
|
||||
"Malagasy": "Malgaix",
|
||||
"Maori": "Maori",
|
||||
"Marathi": "Marathi",
|
||||
"Norwegian Bokmål": "Bokmål Noruec",
|
||||
"Nyanja": "Nyanja",
|
||||
"Portuguese (Brazil)": "Portuguès (Brazil)",
|
||||
"Punjabi": "Panjabi",
|
||||
"Russian (auto-generated)": "Rus (generat automàticament)",
|
||||
"Samoan": "Samoà",
|
||||
"Somali": "Somali",
|
||||
"Southern Sotho": "Sesotho",
|
||||
"Spanish (Mexico)": "Espanyol (Mèxic)",
|
||||
"Spanish (Spain)": "Espanyol (Espanya)",
|
||||
"Sundanese": "Sondanès",
|
||||
"Swahili": "Suahili",
|
||||
"Tamil": "Tàmil",
|
||||
"Telugu": "Telugu",
|
||||
"Zulu": "Zulu",
|
||||
"generic_count_months": "{{count}} mes",
|
||||
"generic_count_months_plural": "{{count}} mesos",
|
||||
"generic_count_weeks": "{{count}} setmana",
|
||||
"generic_count_weeks_plural": "{{count}} setmanes",
|
||||
"About": "Sobre",
|
||||
"`x` marked it with a ❤": "`x`marca'l amb un ❤",
|
||||
"Video mode": "Mode de vídeo",
|
||||
"search_filters_features_label": "Característiques",
|
||||
"search_filters_features_option_c_commons": "Creative Commons",
|
||||
"search_filters_features_option_vr180": "VR180",
|
||||
"search_filters_features_option_three_d": "3D",
|
||||
"search_filters_features_option_purchased": "Comprat",
|
||||
"Chinese (Hong Kong)": "Xinès (Hong Kong)",
|
||||
"Chinese (Taiwan)": "Xinès (Taiwan)",
|
||||
"Hmong": "Hmong",
|
||||
"Kazakh": "Kazakh",
|
||||
"Igbo": "Igbo",
|
||||
"Javanese": "Javanès",
|
||||
"Indonesian (auto-generated)": "Indonesi (generat automàticament)",
|
||||
"Interlingue": "Interlingüe",
|
||||
"Khmer": "Khmer",
|
||||
"This channel does not exist.": "Aquest canal no existeix.",
|
||||
"Song: ": "Cançó: ",
|
||||
"channel:`x`": "canal: `x`",
|
||||
"Deleted or invalid channel": "Canal suprimit o no vàlid",
|
||||
"Could not get channel info.": "No s'ha pogut obtenir la informació del canal.",
|
||||
"Could not pull trending pages.": "No s'han pogut extreure les pàgines de tendència.",
|
||||
"comments_view_x_replies": "Veure {{count}} resposta",
|
||||
"comments_view_x_replies_plural": "Veure {{count}} respostes",
|
||||
"Subscriptions": "Subscripcions",
|
||||
"generic_count_seconds": "{{count}} segon",
|
||||
"generic_count_seconds_plural": "{{count}} segons",
|
||||
"channel_tab_shorts_label": "Vídeos curts",
|
||||
"preferences_save_player_pos_label": "Desa la posició de reproducció: ",
|
||||
"crash_page_before_reporting": "Abans d'informar d'un error, assegureu-vos que teniu:",
|
||||
"crash_page_switch_instance": "ha intentat <a href=\"`x`\">utilitzar una altra instància</a>",
|
||||
"crash_page_read_the_faq": "heu llegit les <a href=\"`x`\">Preguntes més freqüents (FAQ)</a>",
|
||||
"crash_page_search_issue": "ha cercat <a href=\"`x`\">problemes existents a GitHub</a>",
|
||||
"User ID is a required field": "L'identificador d'usuari és un camp obligatori",
|
||||
"Password is a required field": "La contrasenya és un camp obligatori",
|
||||
"Wrong username or password": "Nom d'usuari o contrasenya incorrectes",
|
||||
"Password cannot be longer than 55 characters": "La contrasenya no pot tenir més de 55 caràcters",
|
||||
"Invidious Private Feed for `x`": "Feed privat Invidious per a `x`",
|
||||
"generic_views_count": "{{count}} visualització",
|
||||
"generic_views_count_plural": "{{count}} visualitzacions",
|
||||
"generic_videos_count": "{{count}} vídeo",
|
||||
"generic_videos_count_plural": "{{count}} vídeos",
|
||||
"Token is expired, please try again": "El testimoni ha caducat, torna-ho a provar",
|
||||
"English": "Anglès",
|
||||
"Kannada": "Kanarès",
|
||||
"Erroneous token": "Testimoni erroni",
|
||||
"`x` ago": "fa `x`",
|
||||
"Empty playlist": "Llista de reproducció buida",
|
||||
"Playlist does not exist.": "La llista de reproducció no existeix.",
|
||||
"No such user": "No hi ha tal usuari",
|
||||
"Afrikaans": "Afrikàans",
|
||||
"Azerbaijani": "Azerbaidjana",
|
||||
"Cantonese (Hong Kong)": "Cantonès (Hong Kong)",
|
||||
"Chinese": "Xinès",
|
||||
"Chinese (China)": "Xinès (Xina)",
|
||||
"Chinese (Traditional)": "Xinès (Tradicional)",
|
||||
"Dutch": "Holandès",
|
||||
"Dutch (auto-generated)": "Holandès (generat automàticament)",
|
||||
"French (auto-generated)": "Francès (generat automàticament)",
|
||||
"Georgian": "Georgià",
|
||||
"German (auto-generated)": "Alemany (generat automàticament)",
|
||||
"Gujarati": "Gujarati",
|
||||
"Hawaiian": "Hawaià",
|
||||
"generic_count_years": "{{count}} any",
|
||||
"generic_count_years_plural": "{{count}} anys",
|
||||
"Popular": "Popular",
|
||||
"Rating: ": "Valoració: ",
|
||||
"permalink": "enllaç permanent",
|
||||
"preferences_quality_dash_option_worst": "Pitjor",
|
||||
"Yiddish": "Ídix",
|
||||
"preferences_quality_dash_option_auto": "Automàtic",
|
||||
"Western Frisian": "Frisó occidental",
|
||||
"Swedish": "Suec",
|
||||
"Only show latest unwatched video from channel: ": "Mostra només l'últim vídeo no vist del canal: ",
|
||||
"preferences_continue_label": "Reprodueix el següent per defecte: ",
|
||||
"Import YouTube subscriptions": "Importar subscripcions de YouTube",
|
||||
"search_filters_sort_option_rating": "Valoració",
|
||||
"preferences_thin_mode_label": "Mode prim: ",
|
||||
"preferences_quality_option_small": "Petit",
|
||||
"CAPTCHA enabled: ": "activa CAPTCHA: ",
|
||||
"Import and Export Data": "Importar i exportar dades",
|
||||
"preferences_quality_dash_option_360p": "360p",
|
||||
"Popular enabled: ": "Activa popular: ",
|
||||
"Password": "Contrasenya",
|
||||
"Blacklisted regions: ": "Regions a la llista negra: ",
|
||||
"Register": "Registra't",
|
||||
"Shared `x` ago": "Compartit fa `x`",
|
||||
"search_filters_sort_option_views": "Recompte de visualitzacions",
|
||||
"Import Invidious data": "Importa dades JSON d'Invidious",
|
||||
"preferences_related_videos_label": "Mostra vídeos relacionats: ",
|
||||
"preferences_show_nick_label": "Mostra l'àlies a la part superior: ",
|
||||
"Time (h:mm:ss):": "Temps (h:mm:ss):",
|
||||
"Could not fetch comments": "No s'han pogut obtenir els comentaris",
|
||||
"New password": "Nova contrasenya",
|
||||
"preferences_notifications_only_label": "Mostra només notificacions (si n'hi ha): ",
|
||||
"preferences_annotations_label": "Mostra anotacions per defecte: ",
|
||||
"Import FreeTube subscriptions (.db)": "Importar subscripcions de FreeTube (.db)",
|
||||
"Fallback captions: ": "Subtítols alternatius: ",
|
||||
"Log out": "Tancar sessió",
|
||||
"preferences_quality_dash_option_2160p": "2160p",
|
||||
"Unsubscribe": "Cancel·la la subscripció",
|
||||
"Log in/register": "Inicia sessió/registra't",
|
||||
"Nepali": "Nepalí",
|
||||
"Xhosa": "Xosa",
|
||||
"preferences_captions_label": "Subtítols per defecte: ",
|
||||
"preferences_autoplay_label": "Reproducció automàtica: ",
|
||||
"`x` is live": "`x` està en directe",
|
||||
"Uzbek": "Uzbek",
|
||||
"Hausa": "Haussa",
|
||||
"Bosnian": "Bosnià",
|
||||
"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! Sembla que tens JavaScript desactivat. Feu clic aquí per veure els comentaris, tingueu en compte que poden trigar una mica més a carregar-se.",
|
||||
"Password cannot be empty": "La contrasenya no pot estar buida",
|
||||
"preferences_video_loop_label": "Sempre en bucle: ",
|
||||
"preferences_quality_option_dash": "DASH (qualitat adaptativa)",
|
||||
"Change password": "Canvia la contrasenya",
|
||||
"Export data as JSON": "Exporta dades d'Invidious com a JSON",
|
||||
"Wrong answer": "Resposta incorrecta",
|
||||
"Clear watch history": "Neteja l'historial de reproduccions",
|
||||
"Mongolian": "Mongol",
|
||||
"preferences_quality_dash_option_best": "Millor",
|
||||
"Authorize token for `x`?": "Autoritzar testimoni per a `x`?",
|
||||
"Report statistics: ": "Estadístiques de l'informe: ",
|
||||
"Switch Invidious Instance": "Canvia la instància d'Invidious",
|
||||
"History": "Historial",
|
||||
"Portuguese (auto-generated)": "Portuguès (generat automàticament)",
|
||||
"footer_source_code": "Codi font",
|
||||
"videoinfo_youTube_embed_link": "Insereix",
|
||||
"generic_count_minutes": "{{count}} minut",
|
||||
"generic_count_minutes_plural": "{{count}} minuts",
|
||||
"preferences_category_player": "Preferències del reproductor",
|
||||
"Sign In": "Inicia Sessió",
|
||||
"preferences_continue_autoplay_label": "Reprodueix automàticament el següent vídeo: ",
|
||||
"generic_playlists_count": "{{count}} llista de reproducció",
|
||||
"generic_playlists_count_plural": "{{count}} llistes de reproducció",
|
||||
"Delete account?": "Esborrar compte?",
|
||||
"Please log in": "Si us plau inicieu sessió",
|
||||
"Import NewPipe data (.zip)": "Importar dades de NewPipe (.zip)",
|
||||
"Image CAPTCHA": "Imatge CAPTCHA",
|
||||
"channel_tab_streams_label": "Transmissions en directe",
|
||||
"preferences_category_misc": "Preferències diverses",
|
||||
"preferences_annotations_subscribed_label": "Mostra les anotacions per defecte dels canals subscrits? ",
|
||||
"Tajik": "Tadjik",
|
||||
"preferences_player_style_label": "Estil del reproductor: ",
|
||||
"Load more": "Carrega més",
|
||||
"preferences_vr_mode_label": "Vídeos interactius de 360 graus (requereix WebGL): ",
|
||||
"Manage subscriptions": "Gestionar les subscripcions",
|
||||
"preferences_quality_option_medium": "Mitjà",
|
||||
"Editing playlist `x`": "Editant la llista de reproducció `x`",
|
||||
"search_filters_duration_option_medium": "Mitjà (4 - 20 minuts)",
|
||||
"E-mail": "Correu electrònic",
|
||||
"Spanish (auto-generated)": "Castellà (generat automàticament)",
|
||||
"Export": "Exportar",
|
||||
"preferences_quality_dash_option_4320p": "4320p",
|
||||
"JavaScript license information": "Informació de la llicència de JavaScript",
|
||||
"Hidden field \"token\" is a required field": "El camp ocult \"testimoni\" és un camp obligatori",
|
||||
"Shona": "Xona",
|
||||
"Family friendly? ": "Apte per a tots els públics? ",
|
||||
"preferences_quality_dash_label": "Qualitat de vídeo DASH preferida: ",
|
||||
"Hindi": "Hindi",
|
||||
"An alternative front-end to YouTube": "Una interfície alternativa a YouTube",
|
||||
"Export subscriptions as OPML": "Exporta subscripcions com a OPML",
|
||||
"Watch on YouTube": "Veure a YouTube",
|
||||
"Lao": "Laosià",
|
||||
"search_message_change_filters_or_query": "Proveu d'ampliar la vostra consulta de cerca i/o canviar els filtres.",
|
||||
"View YouTube comments": "Veure comentaris de YouTube",
|
||||
"New passwords must match": "Les contrasenyes noves han de coincidir",
|
||||
"Subscription manager": "Gestor de subscripcions",
|
||||
"Premieres in `x`": "Estrena en `x`",
|
||||
"youtube": "YouTube",
|
||||
"Latvian": "Letó",
|
||||
"LIVE": "EN VIU",
|
||||
"Could not create mix.": "No s'ha pogut crear la barreja.",
|
||||
"preferences_speed_label": "Velocitat per defecte: ",
|
||||
"preferences_extend_desc_label": "Amplieu automàticament la descripció del vídeo: ",
|
||||
"popular": "popular",
|
||||
"Erroneous challenge": "Repte erroni",
|
||||
"last": "darrer",
|
||||
"preferences_quality_dash_option_240p": "240p",
|
||||
"preferences_quality_dash_option_720p": "720p",
|
||||
"preferences_quality_dash_option_480p": "480p",
|
||||
"preferences_quality_dash_option_1440p": "1440p",
|
||||
"Previous page": "Pàgina anterior",
|
||||
"Only show latest video from channel: ": "Mostra només l'últim vídeo del canal: ",
|
||||
"unsubscribe": "cancel·la la subscripció",
|
||||
"View playlist on YouTube": "Veure llista de reproducció a YouTube",
|
||||
"Import NewPipe subscriptions (.json)": "Importar subscripcions de NewPipe (.json)",
|
||||
"crash_page_you_found_a_bug": "Heu trobat un error a Invidious!",
|
||||
"Subscribe": "Subscriu-me",
|
||||
"generic_count_days": "{{count}} dia",
|
||||
"generic_count_days_plural": "{{count}} dies",
|
||||
"Trending": "Tendència",
|
||||
"Updated `x` ago": "Actualitzat fa `x`",
|
||||
"Haitian Creole": "Crioll Haitià",
|
||||
"preferences_watch_history_label": "Habilita historial de reproduccions: ",
|
||||
"generic_count_hours": "{{count}} hora",
|
||||
"generic_count_hours_plural": "{{count}} hores",
|
||||
"Malayalam": "Maialàiam",
|
||||
"Clear watch history?": "Neteja historial de reproduccions?",
|
||||
"Import/export data": "Importa/exporta dades",
|
||||
"Sinhala": "Singalès",
|
||||
"Delete playlist": "Eliminar llista de reproducció",
|
||||
"Bangla": "Bengalí",
|
||||
"Italian (auto-generated)": "Italià (generat automàticament)",
|
||||
"License: ": "Llicència: ",
|
||||
"(edited)": "(editat)",
|
||||
"Pashto": "Paixtu",
|
||||
"preferences_dark_mode_label": "Tema: ",
|
||||
"revoke": "revocar",
|
||||
"English (United Kingdom)": "Anglès (Regne Unit)",
|
||||
"preferences_quality_option_hd720": "HD720",
|
||||
"tokens_count": "{{count}} testimoni",
|
||||
"tokens_count_plural": "{{count}} testimonis",
|
||||
"subscriptions_unseen_notifs_count": "{{count}} notificació no vista",
|
||||
"subscriptions_unseen_notifs_count_plural": "{{count}} notificacions no vistes",
|
||||
"generic_subscribers_count": "{{count}} subscriptor",
|
||||
"generic_subscribers_count_plural": "{{count}} subscriptors",
|
||||
"Sindhi": "Sindhi",
|
||||
"Slovenian": "Eslovè",
|
||||
"preferences_feed_menu_label": "Menú del feed: ",
|
||||
"Fallback comments: ": "Comentaris alternatius: ",
|
||||
"Top": "Millors",
|
||||
"preferences_max_results_label": "Nombre de vídeos mostrats al feed: ",
|
||||
"Engagement: ": "Atracció: ",
|
||||
"Redirect homepage to feed: ": "Redirigeix la pàgina d'inici al feed: ",
|
||||
"Standard YouTube license": "Llicència estàndard de YouTube",
|
||||
"Download is disabled": "Les baixades s'han inhabilitat"
|
||||
}
|
@ -1,496 +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í shodovat",
|
||||
"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",
|
||||
"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",
|
||||
"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",
|
||||
"channel_tab_videos_label": "Videa",
|
||||
"channel_tab_community_label": "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",
|
||||
"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",
|
||||
"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",
|
||||
"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ářů"
|
||||
},
|
||||
"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: ",
|
||||
"error_video_not_in_playlist": "Požadované video v tomto playlistu neexistuje. <a href=\"`x`\">Klikněte sem pro navštívení domovské stránky playlistu.</a>",
|
||||
"channel_tab_shorts_label": "Shorts",
|
||||
"channel_tab_playlists_label": "Playlisty",
|
||||
"channel_tab_channels_label": "Kanály",
|
||||
"channel_tab_streams_label": "Živé přenosy",
|
||||
"Music in this video": "Hudba v tomto videu",
|
||||
"Artist: ": "Umělec: ",
|
||||
"Album: ": "Album: ",
|
||||
"Channel Sponsor": "Sponzor kanálu",
|
||||
"Song: ": "Skladba: ",
|
||||
"Standard YouTube license": "Standardní licence YouTube",
|
||||
"Download is disabled": "Stahování je zakázáno",
|
||||
"Import YouTube playlist (.csv)": "Importovat YouTube playlist (.csv)"
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue