mirror of
https://github.com/TeamPiped/Piped.git
synced 2024-11-26 15:37:24 +00:00
commit
a911ffc746
7
.eslintrc.cjs
Normal file
7
.eslintrc.cjs
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
extends: ["plugin:vue/vue3-recommended", "eslint:recommended", "@unocss", "plugin:prettier/recommended"],
|
||||
};
|
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -22,7 +22,7 @@ body:
|
||||
label: Official Instance
|
||||
description: Can the bug be reproduced on the official instance?
|
||||
options:
|
||||
- label: The bug is reproducable on the [official hosted instance](http://piped.video/) or is API related.
|
||||
- label: The bug is reproducible on the [official hosted instance](http://piped.video/), or is API-related.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
@ -58,7 +58,7 @@ body:
|
||||
description: |
|
||||
If applicable, add logs from the JavaScript console and/or backend server.
|
||||
validations:
|
||||
required: true
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
@ -67,6 +67,8 @@ body:
|
||||
If applicable, add browser, and OS with version.
|
||||
placeholder: >-
|
||||
Brave 1.x.x on Arch Linux.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
|
20
.github/workflows/ci.yml
vendored
20
.github/workflows/ci.yml
vendored
@ -8,13 +8,21 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
submodules: 'true'
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: latest
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: "yarn"
|
||||
- run: yarn install --prefer-offline
|
||||
- run: yarn build
|
||||
- run: yarn lint --no-fix
|
||||
cache: "pnpm"
|
||||
- run: pnpm install
|
||||
- run: pnpm build
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: build
|
||||
path: dist
|
||||
- run: pnpm lint --no-fix
|
||||
|
65
.github/workflows/codeql.yml
vendored
Normal file
65
.github/workflows/codeql.yml
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ 'master' ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ 'master' ]
|
||||
schedule:
|
||||
- cron: '42 11 * * 4'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Use only 'java' to analyze code written in Java, Kotlin or both
|
||||
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
2
.github/workflows/deploy-azure.yml
vendored
2
.github/workflows/deploy-azure.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build and Deploy Job
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Build And Deploy
|
||||
|
14
.github/workflows/docker-build.yml
vendored
14
.github/workflows/docker-build.yml
vendored
@ -11,13 +11,17 @@ jobs:
|
||||
build-docker-image:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: latest
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: "yarn"
|
||||
- run: yarn install --prefer-offline
|
||||
- run: yarn build && ./localizefonts.sh && mv dist/ dist-ci/
|
||||
cache: "pnpm"
|
||||
- run: pnpm install
|
||||
- run: pnpm build && ./localizefonts.sh && mv dist/ dist-ci/
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
with:
|
||||
@ -33,7 +37,7 @@ jobs:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.ci
|
||||
|
56
.github/workflows/ipfs-build.yml
vendored
56
.github/workflows/ipfs-build.yml
vendored
@ -1,31 +1,35 @@
|
||||
name: Build and Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
branches:
|
||||
- master
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: "yarn"
|
||||
- run: yarn install --prefer-offline
|
||||
- run: yarn build && ./localizefonts.sh && cp dist/index.html dist/ipfs-404.html
|
||||
- uses: aquiladev/ipfs-action@v0.3.1-alpha.2
|
||||
id: ipfs-add
|
||||
with:
|
||||
path: ./dist
|
||||
service: infura
|
||||
infuraProjectId: ${{ secrets.INFURA_PROJECT_ID }}
|
||||
infuraProjectSecret: ${{ secrets.INFURA_PROJECT_SECRET }}
|
||||
- name: Update DNSLink
|
||||
run: npx dnslink-cloudflare -d kavin.rocks -l /ipfs/${{ steps.ipfs-add.outputs.hash }} -r _dnslink.piped-ipfs
|
||||
env:
|
||||
CF_API_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }}
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: latest
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: "pnpm"
|
||||
- run: pnpm install
|
||||
- run: pnpm build && ./localizefonts.sh && cp dist/index.html dist/ipfs-404.html
|
||||
- uses: aquiladev/ipfs-action@v0.3.1-alpha.2
|
||||
id: ipfs-add
|
||||
with:
|
||||
path: ./dist
|
||||
service: infura
|
||||
infuraProjectId: ${{ secrets.INFURA_PROJECT_ID }}
|
||||
infuraProjectSecret: ${{ secrets.INFURA_PROJECT_SECRET }}
|
||||
- name: Update DNSLink
|
||||
run: npx dnslink-cloudflare -d kavin.rocks -l /ipfs/${{ steps.ipfs-add.outputs.hash }} -r _dnslink.piped-ipfs
|
||||
env:
|
||||
CF_API_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }}
|
||||
|
25
.github/workflows/reviewdog.yml
vendored
Normal file
25
.github/workflows/reviewdog.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: reviewdog
|
||||
on: [pull_request]
|
||||
jobs:
|
||||
eslint:
|
||||
name: runner / eslint
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: latest
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: "pnpm"
|
||||
- run: pnpm install
|
||||
- uses: reviewdog/action-eslint@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
reporter: github-pr-review
|
||||
eslint_flags: "--ignore-path .gitignore --ext .js,.vue ."
|
6
.github/workflows/weblate-merge.yml
vendored
6
.github/workflows/weblate-merge.yml
vendored
@ -8,6 +8,12 @@ jobs:
|
||||
merge:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Check if en.json has been updated
|
||||
run: |
|
||||
if -n git diff ${{ github.event.pull_request.base.sha }}..${{ github.sha }} src/locales/en.json; then
|
||||
exit 1
|
||||
fi
|
||||
- name: AutoMerge Weblate translations
|
||||
if: github.event.pull_request.user.login == 'weblate'
|
||||
run: gh pr merge --auto --delete-branch --merge "$PR_URL"
|
||||
|
106
CODE_OF_CONDUCT.md
Normal file
106
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,106 @@
|
||||
# Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior include but are not limited to:
|
||||
|
||||
- The usage of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
- Trolling, insulting/derogatory comments, threats, and personal or political attacks
|
||||
- Harassment of any form
|
||||
- Publishing others' private information, such as a physical or electronic address, without explicit permission from the individual
|
||||
- Derailling conversations unnecessarily in a way that is not constructive, such as repeatedly posting off-topic comments whilest not in an off-topic channel
|
||||
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
- Tagging maintainers or project members without being one yourself
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at the contact section of the project README, or alternatively any admin of an official medium community. All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private or public, written warning from community leaders, providing
|
||||
clarity when necessary around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A written warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Kick / Temporary Ban
|
||||
|
||||
**Community Impact**: A serious or repeated violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A kick or temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
@ -8,10 +8,12 @@ RUN --mount=type=cache,target=/var/cache/apk \
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN --mount=type=cache,target=/root/.cache/yarn \
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
|
||||
RUN --mount=type=cache,target=/root/.local/share/pnpm \
|
||||
--mount=type=cache,target=/app/node_modules \
|
||||
yarn install --prefer-offline && \
|
||||
yarn build && ./localizefonts.sh
|
||||
pnpm install --prefer-offline && \
|
||||
pnpm build && ./localizefonts.sh
|
||||
|
||||
FROM nginx:alpine
|
||||
|
||||
|
17
README.md
17
README.md
@ -2,6 +2,7 @@
|
||||
|
||||
[![AGPL v3](https://shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
[![Matrix](https://img.shields.io/matrix/piped:matrix.org)](https://matrix.to/#/#piped:matrix.org)
|
||||
[![Lemmy](https://img.shields.io/lemmy/piped%40feddit.rocks)](https://feddit.rocks/c/piped)
|
||||
[![Registered Users](https://pipedapi.kavin.rocks/registered/badge)](https://piped.video/register)
|
||||
[![IPFS Build](https://github.com/TeamPiped/Piped/actions/workflows/ipfs-build.yml/badge.svg)](https://piped-ipfs.kavin.rocks/)
|
||||
[![GitHub Repo stars](https://img.shields.io/github/stars/TeamPiped/Piped-Frontend?style=social)](https://github.com/TeamPiped/Piped/stargazers)
|
||||
@ -61,6 +62,10 @@ By using Piped, you can freely watch and listen to content without the fear of p
|
||||
- You can join us via Matrix at [#piped](https://matrix.to/#/#piped:matrix.org).
|
||||
- You can also join us at the libera.chat IRC network which is bridged to the Matrix room at [#piped](https://web.libera.chat/#piped).
|
||||
|
||||
## Public Communities
|
||||
|
||||
- You can join us on Lemmy on the [!piped@feddit.rocks](https://feddit.rocks/c/piped) community.
|
||||
|
||||
## Self-Hosting
|
||||
|
||||
See https://docs.piped.video/docs/self-hosting/ for more details.
|
||||
@ -103,13 +108,13 @@ You can help by translating the project to a language you speak at https://hoste
|
||||
### Development Setup
|
||||
|
||||
```
|
||||
yarn install
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
|
||||
```
|
||||
yarn serve
|
||||
pnpm serve
|
||||
```
|
||||
|
||||
You can now make changes and view then in realtime!
|
||||
@ -140,7 +145,15 @@ Contributions in any other form are also welcomed.
|
||||
|
||||
- [Yattee](https://github.com/yattee/yattee) - an alternative frontend for YouTube, for IOS.
|
||||
- [LibreTube](https://github.com/Libre-tube/LibreTube) - an alternative frontend for YouTube, for Android.
|
||||
- [Racoon](https://github.com/shailendramaurya/racoon) - A web based minimal YouTube downloader.
|
||||
- [Hyperpipe](https://codeberg.org/Hyperpipe/Hyperpipe) - an alternative privacy respecting frontend for YouTube Music.
|
||||
- [Musicale](https://github.com/Bellisario/musicale) - an alternative to YouTube Music, with style.
|
||||
- [ytify](https://github.com/n-ce/ytify) - a complementary minimal audio streaming frontend for YouTube.
|
||||
- [PsTube](https://github.com/prateekmedia/pstube) - Watch and download videos without ads on Android, Linux, Windows, iOS, and Mac OSX.
|
||||
- [Piped-Material](https://github.com/mmjee/Piped-Material) - A fork of Piped, focusing on better performance and a more usable design.
|
||||
- [ReacTube](https://github.com/NeeRaj-2401/ReacTube) - Privacy friendly & distraction free Youtube front-end using Piped API.
|
||||
- [YTDLnis](https://github.com/deniscerri/ytdlnis) - Video and audio downloader for Android that uses Piped to update formats.
|
||||
- [DeskVideo](https://github.com/malisipi/DeskVideo) - A desktop styled, customizable alternative front-end for YouTube.
|
||||
|
||||
## YourKit
|
||||
|
||||
|
@ -2,6 +2,7 @@ server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name localhost;
|
||||
error_log off;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html style="background: #0f0f0f" lang="en">
|
||||
<html style="background: #0f0f0f" lang="en" >
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
@ -7,6 +7,7 @@
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link title="Piped" type="application/opensearchdescription+xml" rel="search" href="/opensearch.xml" />
|
||||
<title>Piped</title>
|
||||
<meta name="theme-color" content="#0f0f0f">
|
||||
<meta property="og:title" content="Piped" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:image" content="/img/icons/favicon-32x32.png" />
|
||||
|
@ -3,7 +3,7 @@
|
||||
base='https://fonts\.(gstatic\.com|kavin\.rocks)'
|
||||
fonts=$(cat dist/assets/* | grep -Po "$base[^)]*" | sort | uniq)
|
||||
for font in $fonts; do
|
||||
file="dist/fonts$(echo $font | sed -E "s#$base##")"
|
||||
file="dist/fonts$(echo "$font" | sed -E "s#$base##")"
|
||||
mkdir -p "$(dirname "$file")"
|
||||
curl -L "$font" -o "$file"
|
||||
done
|
||||
|
76
package.json
76
package.json
@ -6,56 +6,54 @@
|
||||
"serve": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"format": "prettier -w --ignore-path .gitignore **/**.{js,vue,json}",
|
||||
"lint": "eslint --fix --color --ignore-path .gitignore --ext .js,.vue ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "6.2.1",
|
||||
"@fortawesome/free-brands-svg-icons": "6.2.1",
|
||||
"@fortawesome/free-solid-svg-icons": "6.2.1",
|
||||
"@fortawesome/vue-fontawesome": "3.0.2",
|
||||
"@fortawesome/fontawesome-svg-core": "6.4.2",
|
||||
"@fortawesome/free-brands-svg-icons": "6.4.2",
|
||||
"@fortawesome/free-solid-svg-icons": "6.4.2",
|
||||
"@fortawesome/vue-fontawesome": "3.0.3",
|
||||
"buffer": "6.0.3",
|
||||
"dompurify": "2.4.2",
|
||||
"hotkeys-js": "3.10.1",
|
||||
"dompurify": "3.0.5",
|
||||
"hotkeys-js": "3.12.0",
|
||||
"javascript-time-ago": "2.5.9",
|
||||
"mux.js": "6.2.0",
|
||||
"shaka-player": "4.3.2",
|
||||
"linkify-html": "4.1.1",
|
||||
"linkifyjs": "4.1.1",
|
||||
"mux.js": "6.3.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"shaka-player": "4.4.0",
|
||||
"stream-browserify": "3.0.0",
|
||||
"vue": "3.2.45",
|
||||
"vue": "3.3.4",
|
||||
"vue-i18n": "9.2.2",
|
||||
"vue-router": "4.1.6",
|
||||
"vue-router": "4.2.4",
|
||||
"xml-js": "1.6.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/json": "2.2.3",
|
||||
"@intlify/vite-plugin-vue-i18n": "6.0.3",
|
||||
"@unocss/preset-icons": "0.48.2",
|
||||
"@unocss/preset-web-fonts": "0.48.2",
|
||||
"@unocss/transformer-directives": "0.48.2",
|
||||
"@unocss/transformer-variant-group": "0.48.2",
|
||||
"@vitejs/plugin-legacy": "3.0.1",
|
||||
"@vitejs/plugin-vue": "4.0.0",
|
||||
"@vue/compiler-sfc": "3.2.45",
|
||||
"eslint": "8.31.0",
|
||||
"eslint-config-prettier": "8.6.0",
|
||||
"eslint-plugin-prettier": "4.2.1",
|
||||
"eslint-plugin-vue": "9.8.0",
|
||||
"prettier": "2.8.1",
|
||||
"unocss": "0.48.2",
|
||||
"vite": "3.2.5",
|
||||
"@iconify-json/fa6-brands": "1.1.13",
|
||||
"@iconify-json/fa6-solid": "1.1.15",
|
||||
"@intlify/unplugin-vue-i18n": "0.13.0",
|
||||
"@unocss/eslint-config": "0.55.6",
|
||||
"@unocss/preset-icons": "0.55.6",
|
||||
"@unocss/preset-uno": "0.55.6",
|
||||
"@unocss/preset-web-fonts": "0.55.6",
|
||||
"@unocss/reset": "0.55.6",
|
||||
"@unocss/transformer-directives": "0.55.6",
|
||||
"@unocss/transformer-variant-group": "0.55.6",
|
||||
"@vitejs/plugin-legacy": "4.1.1",
|
||||
"@vitejs/plugin-vue": "4.3.4",
|
||||
"@vue/compiler-sfc": "3.3.4",
|
||||
"eslint": "8.48.0",
|
||||
"eslint-config-prettier": "9.0.0",
|
||||
"eslint-plugin-prettier": "5.0.0",
|
||||
"eslint-plugin-vue": "9.17.0",
|
||||
"lightningcss": "1.21.7",
|
||||
"prettier": "3.0.3",
|
||||
"unocss": "0.55.6",
|
||||
"vite": "4.4.9",
|
||||
"vite-plugin-eslint": "1.8.1",
|
||||
"vite-plugin-pwa": "0.14.1"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/vue3-essential",
|
||||
"plugin:prettier/recommended",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"rules": {}
|
||||
"vite-plugin-pwa": "0.16.4",
|
||||
"workbox-window": "7.0.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"last 1 chrome version",
|
||||
|
5397
pnpm-lock.yaml
Normal file
5397
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load Diff
@ -1 +1 @@
|
||||
Subproject commit 79329007824820dedf4234200f105b9d4caac577
|
||||
Subproject commit 1e7e82b64b9f8354641f0665f61c7983c9dfed27
|
@ -1,21 +1,17 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base",
|
||||
"group:recommended"
|
||||
],
|
||||
"ignorePresets": [
|
||||
":prHourlyLimit2"
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchPackagePrefixes": [
|
||||
"@unocss/"
|
||||
],
|
||||
"matchPackageNames": [
|
||||
"unocss"
|
||||
],
|
||||
"groupName": "unocss"
|
||||
}
|
||||
]
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["config:base", "group:recommended"],
|
||||
"ignorePresets": [":prHourlyLimit2"],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchPackagePrefixes": ["@unocss/"],
|
||||
"matchPackageNames": ["unocss"],
|
||||
"groupName": "unocss"
|
||||
}
|
||||
],
|
||||
"lockFileMaintenance": {
|
||||
"enabled": true,
|
||||
"automerge": true
|
||||
},
|
||||
"platformAutomerge": true
|
||||
}
|
||||
|
112
src/App.vue
112
src/App.vue
@ -1,18 +1,22 @@
|
||||
<template>
|
||||
<div>
|
||||
<NavBar />
|
||||
|
||||
<NavBar />
|
||||
<div class="flex-1">
|
||||
<router-view v-slot="{ Component }">
|
||||
<keep-alive :max="5">
|
||||
<component :is="Component" :key="$route.fullPath" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
|
||||
<FooterComponent />
|
||||
</div>
|
||||
<FooterComponent />
|
||||
</template>
|
||||
|
||||
<style>
|
||||
#app {
|
||||
min-height: calc(var(--efy_100vh) - var(--efy_gap2));
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/*Radius*/
|
||||
input,
|
||||
.btn,
|
||||
@ -32,9 +36,8 @@ video {
|
||||
border-radius: var(--efy_radius) !important;
|
||||
}
|
||||
|
||||
/*Radius 0*/
|
||||
.video-grid img {
|
||||
border-radius: var(--efy_radius0);
|
||||
.video-card .thumbnail {
|
||||
border-radius: var(--efy_radius) var(--efy_radius) 0 0;
|
||||
}
|
||||
|
||||
/*Radius 2*/
|
||||
@ -61,14 +64,17 @@ video {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
margin: 0 0 5rem 0;
|
||||
padding: 0 10rem 5rem 10rem;
|
||||
line-height: 22rem;
|
||||
max-height: 43rem;
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
}
|
||||
.pp-video-card-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--efy_gap0);
|
||||
margin: 5rem 0 0;
|
||||
margin: 5rem 10rem 10rem 10rem;
|
||||
}
|
||||
.pp-video-card-buttons :is(a, button) {
|
||||
padding: 4rem 8rem;
|
||||
@ -85,6 +91,8 @@ video {
|
||||
-webkit-text-fill-color: var(--efy_text2);
|
||||
border: 0;
|
||||
padding: 6rem 10rem;
|
||||
}
|
||||
.pp-video-card-buttons :is(.pp-color, .btn, button) {
|
||||
height: 35rem;
|
||||
}
|
||||
.pp-video-card-channel > .pp-text {
|
||||
@ -113,8 +121,9 @@ video {
|
||||
gap: var(--efy_gap0);
|
||||
place-items: center;
|
||||
background: transparent;
|
||||
margin: var(--efy_gap0) 0 0;
|
||||
margin: var(--efy_gap0) 0 var(--efy_gap0) var(--efy_gap0);
|
||||
width: fit-content;
|
||||
border-radius: var(--efy_radius);
|
||||
}
|
||||
.pp-video-card-channel > a {
|
||||
height: 36rem;
|
||||
@ -141,38 +150,46 @@ export default {
|
||||
theme: "dark",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
setTheme() {
|
||||
let themePref = this.getPreferenceString("theme", "dark");
|
||||
if (themePref == "auto") this.theme = darkModePreference.matches ? "dark" : "light";
|
||||
else this.theme = themePref;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.setTheme();
|
||||
darkModePreference.addEventListener("change", () => {
|
||||
this.setTheme();
|
||||
});
|
||||
if (this.getPreferenceBoolean("watchHistory", false))
|
||||
if ("indexedDB" in window) {
|
||||
const request = indexedDB.open("piped-db", 2);
|
||||
request.onupgradeneeded = ev => {
|
||||
const db = request.result;
|
||||
console.log("Upgrading object store.");
|
||||
if (!db.objectStoreNames.contains("watch_history")) {
|
||||
const store = db.createObjectStore("watch_history", { keyPath: "videoId" });
|
||||
store.createIndex("video_id_idx", "videoId", { unique: true });
|
||||
store.createIndex("id_idx", "id", { unique: true, autoIncrement: true });
|
||||
}
|
||||
if (ev.oldVersion < 2) {
|
||||
const store = request.transaction.objectStore("watch_history");
|
||||
store.createIndex("watchedAt", "watchedAt", { unique: false });
|
||||
}
|
||||
};
|
||||
request.onsuccess = e => {
|
||||
window.db = e.target.result;
|
||||
};
|
||||
} else console.log("This browser doesn't support IndexedDB");
|
||||
|
||||
if ("indexedDB" in window) {
|
||||
const request = indexedDB.open("piped-db", 5);
|
||||
request.onupgradeneeded = ev => {
|
||||
const db = request.result;
|
||||
console.log("Upgrading object store.");
|
||||
if (!db.objectStoreNames.contains("watch_history")) {
|
||||
const store = db.createObjectStore("watch_history", { keyPath: "videoId" });
|
||||
store.createIndex("video_id_idx", "videoId", { unique: true });
|
||||
store.createIndex("id_idx", "id", { unique: true, autoIncrement: true });
|
||||
}
|
||||
if (ev.oldVersion < 2) {
|
||||
const store = request.transaction.objectStore("watch_history");
|
||||
store.createIndex("watchedAt", "watchedAt", { unique: false });
|
||||
}
|
||||
if (!db.objectStoreNames.contains("playlist_bookmarks")) {
|
||||
const store = db.createObjectStore("playlist_bookmarks", { keyPath: "playlistId" });
|
||||
store.createIndex("playlist_id_idx", "playlistId", { unique: true });
|
||||
store.createIndex("id_idx", "id", { unique: true, autoIncrement: true });
|
||||
}
|
||||
if (!db.objectStoreNames.contains("channel_groups")) {
|
||||
const store = db.createObjectStore("channel_groups", { keyPath: "groupName" });
|
||||
store.createIndex("groupName", "groupName", { unique: true });
|
||||
}
|
||||
if (!db.objectStoreNames.contains("playlists")) {
|
||||
const playlistStore = db.createObjectStore("playlists", { keyPath: "playlistId" });
|
||||
playlistStore.createIndex("playlistId", "playlistId", { unique: true });
|
||||
const playlistVideosStore = db.createObjectStore("playlist_videos", { keyPath: "videoId" });
|
||||
playlistVideosStore.createIndex("videoId", "videoId", { unique: true });
|
||||
}
|
||||
};
|
||||
request.onsuccess = e => {
|
||||
window.db = e.target.result;
|
||||
};
|
||||
} else console.log("This browser doesn't support IndexedDB");
|
||||
|
||||
const App = this;
|
||||
|
||||
@ -197,5 +214,24 @@ export default {
|
||||
}
|
||||
})();
|
||||
},
|
||||
methods: {
|
||||
setTheme() {
|
||||
let themePref = this.getPreferenceString("theme", "dark");
|
||||
if (themePref == "auto") this.theme = darkModePreference.matches ? "dark" : "light";
|
||||
else this.theme = themePref;
|
||||
|
||||
// Change title bar color based on user's theme
|
||||
const themeColor = document.querySelector("meta[name='theme-color']");
|
||||
if (this.theme === "light") {
|
||||
themeColor.setAttribute("content", "#FFF");
|
||||
} else {
|
||||
themeColor.setAttribute("content", "#0F0F0F");
|
||||
}
|
||||
|
||||
// Used for the scrollbar
|
||||
const root = document.querySelector(":root");
|
||||
this.theme == "dark" ? root.classList.add("dark") : root.classList.remove("dark");
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -1,34 +1,35 @@
|
||||
<template>
|
||||
<div>
|
||||
<router-link :to="props.item.url">
|
||||
<div class="relative">
|
||||
<img class="w-full" :src="props.item.thumbnail" loading="lazy" />
|
||||
<div class="flex flex-col efy_trans_filter efy_shadow_trans">
|
||||
<router-link
|
||||
:to="props.item.url"
|
||||
class="flex items-center p-[10rem] gap-[10rem]"
|
||||
style="border-bottom: var(--efy_border)"
|
||||
>
|
||||
<img
|
||||
class="efy_shadow_trans"
|
||||
style="border-radius: var(--efy_radius); width: 40rem; aspect-ratio: 1"
|
||||
:src="props.item.thumbnail"
|
||||
loading="lazy"
|
||||
width="40"
|
||||
height="40"
|
||||
/>
|
||||
<div class="flex items-center overflow-hidden pp-text">
|
||||
<p v-text="props.item.name" class="pp-video-card-title p-0!" />
|
||||
<font-awesome-icon v-if="props.item.verified" class="ml-1.5" icon="check" />
|
||||
</div>
|
||||
<p>
|
||||
<span v-text="props.item.name" />
|
||||
<font-awesome-icon class="ml-1.5" v-if="props.item.verified" icon="check" />
|
||||
</p>
|
||||
</router-link>
|
||||
<p v-if="props.item.description" v-text="props.item.description" />
|
||||
<router-link v-if="props.item.uploaderUrl" class="link" :to="props.item.uploaderUrl">
|
||||
<p>
|
||||
<span v-text="props.item.uploader" />
|
||||
<font-awesome-icon class="ml-1.5" v-if="props.item.uploaderVerified" icon="check" />
|
||||
</p>
|
||||
</router-link>
|
||||
|
||||
<a v-if="props.item.uploaderName" class="link" v-text="props.item.uploaderName" />
|
||||
<template v-if="props.item.videos >= 0">
|
||||
<br v-if="props.item.uploaderName" />
|
||||
<strong v-text="`${props.item.videos} ${$t('video.videos')}`" />
|
||||
</template>
|
||||
|
||||
<br />
|
||||
<div style="padding: 10rem">
|
||||
<p v-if="props.item.description" v-text="props.item.description" />
|
||||
<div v-if="props.item.videos >= 0" v-text="`${props.item.videos} ${$t('video.videos')}`" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
item: Object,
|
||||
item: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
@ -1,88 +1,94 @@
|
||||
<template>
|
||||
<ErrorHandler v-if="channel && channel.error" :message="channel.message" :error="channel.error" />
|
||||
<div v-if="channel" v-show="!channel.error" class="mt-[15rem]">
|
||||
<LoadingIndicatorPage :show-content="channel != null && !channel.error">
|
||||
<img v-if="channel.bannerUrl" :src="channel.bannerUrl" class="w-full efy_shadow_trans" loading="lazy" />
|
||||
<div class="pp-channel-page-author flex">
|
||||
<img height="48" width="48" class="efy_shadow_trans" :src="channel.avatarUrl" />
|
||||
<h5 v-text="channel.name" />
|
||||
<font-awesome-icon v-if="channel.verified" class="ml-1.5" icon="check" />
|
||||
</div>
|
||||
<p v-text="channel.description" style="margin: 10rem 0 0 0" />
|
||||
|
||||
<div v-if="channel" v-show="!channel.error">
|
||||
<img v-if="channel.bannerUrl" :src="channel.bannerUrl" class="w-full pb-1.5" loading="lazy" />
|
||||
<div class="pp-channel-page-author flex place-items-center">
|
||||
<img height="48" width="48" class="m-1" :src="channel.avatarUrl" />
|
||||
<h5 v-text="channel.name" />
|
||||
<font-awesome-icon class="ml-1.5" v-if="channel.verified" icon="check" />
|
||||
</div>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<p class="whitespace-pre-wrap mt-2">
|
||||
<span v-html="purifyHTML(urlify(channel.description))" />
|
||||
</p>
|
||||
<div class="pp-channel-tabs">
|
||||
<button
|
||||
v-t="{
|
||||
path: `actions.${subscribed ? 'unsubscribe' : 'subscribe'}`,
|
||||
args: { count: numberFormat(channel.subscriberCount) },
|
||||
}"
|
||||
class="pp-subscribe"
|
||||
@click="subscribeHandler"
|
||||
></button>
|
||||
|
||||
<div class="flex mt-4 mb-2 pp-channel-tabs">
|
||||
<button
|
||||
class="btn pp-subscribe"
|
||||
@click="subscribeHandler"
|
||||
v-t="{
|
||||
path: `actions.${subscribed ? 'unsubscribe' : 'subscribe'}`,
|
||||
args: { count: numberFormat(channel.subscriberCount) },
|
||||
}"
|
||||
></button>
|
||||
<!-- RSS Feed button -->
|
||||
<a
|
||||
v-if="channel.id"
|
||||
aria-label="RSS feed"
|
||||
title="RSS feed"
|
||||
role="button"
|
||||
:href="`${apiUrl()}/feed/unauthenticated/rss?channels=${channel.id}`"
|
||||
target="_blank"
|
||||
class="pp-square"
|
||||
style="display: inline; float: unset"
|
||||
>
|
||||
<font-awesome-icon icon="rss" />
|
||||
</a>
|
||||
<WatchOnButton :link="`https://youtube.com/channel/${channel.id}`" />
|
||||
<p style="place-self: center">|</p>
|
||||
<button
|
||||
v-for="(tab, index) in tabs"
|
||||
:key="tab.name"
|
||||
:class="{ active: selectedTab == index }"
|
||||
@click="loadTab(index)"
|
||||
>
|
||||
<span v-text="tab.translatedName"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- RSS Feed button -->
|
||||
<a
|
||||
aria-label="RSS feed"
|
||||
title="RSS feed"
|
||||
role="button"
|
||||
v-if="channel.id"
|
||||
:href="`${apiUrl()}/feed/unauthenticated/rss?channels=${channel.id}`"
|
||||
target="_blank"
|
||||
class="btn"
|
||||
style="display: inline; float: unset; margin-left: var(--efy_gap0)"
|
||||
>
|
||||
<font-awesome-icon icon="rss" />
|
||||
</a>
|
||||
<WatchOnYouTubeButton :link="`https://youtube.com/channel/${this.channel.id}`" />
|
||||
<p>|</p>
|
||||
<button
|
||||
v-for="(tab, index) in tabs"
|
||||
:key="tab.name"
|
||||
style="margin-right: var(--efy_gap0)"
|
||||
@click="loadTab(index)"
|
||||
:class="{ active: selectedTab == index }"
|
||||
>
|
||||
<span v-text="tab.translatedName"></span>
|
||||
</button>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="video-grid">
|
||||
<ContentItem
|
||||
v-for="item in contentItems"
|
||||
:key="item.url"
|
||||
:item="item"
|
||||
height="94"
|
||||
width="168"
|
||||
hide-channel
|
||||
class="efy_trans_filter"
|
||||
/>
|
||||
</div>
|
||||
<div class="video-grid">
|
||||
<ContentItem
|
||||
v-for="item in contentItems"
|
||||
:key="item.url"
|
||||
:item="item"
|
||||
height="94"
|
||||
width="168"
|
||||
hide-channel
|
||||
class="efy_trans_filter"
|
||||
/>
|
||||
</div>
|
||||
</LoadingIndicatorPage>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.pp-channel-tabs > p {
|
||||
place-self: center;
|
||||
padding: 0 10rem;
|
||||
-webkit-text-fill-color: var(--efy_text_trans2);
|
||||
.pp-channel-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 15rem 0;
|
||||
gap: var(--efy_gap0);
|
||||
}
|
||||
.pp-channel-tabs :is(button, [role="button"]) {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import ErrorHandler from "./ErrorHandler.vue";
|
||||
import ContentItem from "./ContentItem.vue";
|
||||
import WatchOnYouTubeButton from "./WatchOnYouTubeButton.vue";
|
||||
import WatchOnButton from "./WatchOnButton.vue";
|
||||
import LoadingIndicatorPage from "./LoadingIndicatorPage.vue";
|
||||
// import CollapsableText from "./CollapsableText.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ErrorHandler,
|
||||
ContentItem,
|
||||
WatchOnYouTubeButton,
|
||||
WatchOnButton,
|
||||
LoadingIndicatorPage,
|
||||
// CollapsableText,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -130,7 +136,9 @@ export default {
|
||||
});
|
||||
},
|
||||
async fetchChannel() {
|
||||
const url = this.apiUrl() + "/" + this.$route.params.path + "/" + this.$route.params.channelId;
|
||||
const url = this.$route.path.includes("@")
|
||||
? this.apiUrl() + "/@/" + this.$route.params.channelId
|
||||
: this.apiUrl() + "/" + this.$route.params.path + "/" + this.$route.params.channelId;
|
||||
return await this.fetchJson(url);
|
||||
},
|
||||
async getChannelData() {
|
||||
@ -142,13 +150,16 @@ export default {
|
||||
this.contentItems = this.channel.relatedStreams;
|
||||
this.fetchSubscribedStatus();
|
||||
this.updateWatched(this.channel.relatedStreams);
|
||||
this.fetchDeArrowContent(this.channel.relatedStreams);
|
||||
this.tabs.push({
|
||||
translatedName: this.$t("video.videos"),
|
||||
});
|
||||
const tabQuery = this.$route.query.tab;
|
||||
for (let i = 0; i < this.channel.tabs.length; i++) {
|
||||
let tab = this.channel.tabs[i];
|
||||
tab.translatedName = this.getTranslatedTabName(tab.name);
|
||||
this.tabs.push(tab);
|
||||
if (tab.name === tabQuery) this.loadTab(i + 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -178,6 +189,7 @@ export default {
|
||||
this.loading = false;
|
||||
this.updateWatched(json.relatedStreams);
|
||||
json.relatedStreams.map(stream => this.contentItems.push(stream));
|
||||
this.fetchDeArrowContent(this.contentItems);
|
||||
});
|
||||
},
|
||||
fetchChannelTabNextPage() {
|
||||
@ -188,6 +200,7 @@ export default {
|
||||
this.tabs[this.selectedTab].tabNextPage = json.nextpage;
|
||||
this.loading = false;
|
||||
json.content.map(item => this.contentItems.push(item));
|
||||
this.fetchDeArrowContent(this.contentItems);
|
||||
this.tabs[this.selectedTab].content = this.contentItems;
|
||||
});
|
||||
},
|
||||
@ -231,10 +244,17 @@ export default {
|
||||
},
|
||||
loadTab(index) {
|
||||
this.selectedTab = index;
|
||||
|
||||
// update the tab query in the url path
|
||||
const url = new URL(window.location);
|
||||
url.searchParams.set("tab", this.tabs[index].name ?? "videos");
|
||||
window.history.replaceState(window.history.state, "", url);
|
||||
|
||||
if (index == 0) {
|
||||
this.contentItems = this.channel.relatedStreams;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.tabs[index].content) {
|
||||
this.contentItems = this.tabs[index].content;
|
||||
return;
|
||||
@ -243,6 +263,7 @@ export default {
|
||||
data: this.tabs[index].data,
|
||||
}).then(tab => {
|
||||
this.contentItems = this.tabs[index].content = tab.content;
|
||||
this.fetchDeArrowContent(this.contentItems);
|
||||
this.tabs[this.selectedTab].tabNextPage = tab.nextpage;
|
||||
});
|
||||
},
|
||||
|
@ -1,15 +1,16 @@
|
||||
<template>
|
||||
<!-- desktop view -->
|
||||
<div v-if="!mobileLayout" class="pp-chapters flex-col overflow-y-scroll max-h-75vh min-h-64 lt-lg:hidden">
|
||||
<h6 aria-label="chapters" title="chapters" class="efy_trans_filter">
|
||||
<div v-if="!mobileLayout" class="pp-chapters flex-col max-h-75vh min-h-64 lt-lg:hidden">
|
||||
<h6 aria-label="chapters" title="chapters" class="efy_trans_filter efy_shadow_trans">
|
||||
{{ $t("video.chapters") }} - {{ chapters.length }}
|
||||
</h6>
|
||||
<div
|
||||
:key="chapter.start"
|
||||
v-for="(chapter, index) in chapters"
|
||||
:key="chapter.start"
|
||||
class="chapter efy_anim_pulse"
|
||||
:class="isCurrentChapter(index) ? 'pp-chapter-active' : 'efy_shadow_trans efy_trans_filter'"
|
||||
:role="isCurrentChapter(index) ? 'button' : ''"
|
||||
@click="$emit('seek', chapter.start)"
|
||||
class="chapter efy_anim_pulse efy_trans_filter"
|
||||
:class="{ 'pp-chapter-active': isCurrentChapter(index) }"
|
||||
>
|
||||
<div class="flex">
|
||||
<img :src="chapter.image" :alt="chapter.title" />
|
||||
@ -23,11 +24,11 @@
|
||||
<!-- mobile view -->
|
||||
<div v-else class="pp-chapters pp-mobile flex overflow-x-auto">
|
||||
<div
|
||||
:key="chapter.start"
|
||||
v-for="(chapter, index) in chapters"
|
||||
@click="$emit('seek', chapter.start)"
|
||||
:key="chapter.start"
|
||||
class="chapter efy_anim_pulse efy_trans_filter"
|
||||
:class="{ 'pp-chapter-active': isCurrentChapter(index) }"
|
||||
@click="$emit('seek', chapter.start)"
|
||||
>
|
||||
<img :src="chapter.image" :alt="chapter.title" />
|
||||
<div class="m-1 flex">
|
||||
@ -38,24 +39,12 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.chapter {
|
||||
@apply cursor-pointer self-center p-2.5;
|
||||
}
|
||||
.pp-mobile .chapter img {
|
||||
@apply w-full h-full;
|
||||
}
|
||||
.chapter img {
|
||||
@apply w-3/10 h-3/10;
|
||||
}
|
||||
.text-truncate {
|
||||
@apply truncate overflow-hidden inline-block w-10em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
chapters: Object,
|
||||
chapters: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
mobileLayout: {
|
||||
type: Boolean,
|
||||
default: () => true,
|
||||
@ -75,3 +64,51 @@ const isCurrentChapter = index => {
|
||||
|
||||
defineEmits(["seek"]);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.chapter {
|
||||
@apply cursor-pointer self-center p-2.5;
|
||||
}
|
||||
.pp-mobile .chapter img {
|
||||
@apply w-full h-full;
|
||||
}
|
||||
.chapter img {
|
||||
@apply w-3/10 h-3/10;
|
||||
}
|
||||
.text-truncate {
|
||||
@apply truncate overflow-hidden inline-block w-10em;
|
||||
}
|
||||
.pp-chapters {
|
||||
margin: -15rem 0 0 0;
|
||||
padding: var(--efy_gap);
|
||||
max-width: 400rem;
|
||||
gap: var(--efy_gap0);
|
||||
border-radius: var(--efy_radius);
|
||||
overflow: auto;
|
||||
}
|
||||
.pp-chapters .chapter {
|
||||
padding: 10rem;
|
||||
border-radius: var(--efy_radius);
|
||||
border: var(--efy_border);
|
||||
}
|
||||
.pp-chapters [title="chapters"] {
|
||||
padding: 5rem 10rem;
|
||||
border-radius: var(--efy_radius);
|
||||
border: var(--efy_border);
|
||||
}
|
||||
.pp-chapters .chapter .flex {
|
||||
gap: 0 15rem;
|
||||
}
|
||||
.pp-chapters.pp-mobile {
|
||||
margin: 15rem 0 0 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
.pp-chapter-active,
|
||||
.pp-chapters .chapter:hover {
|
||||
background: var(--efy_color);
|
||||
background-clip: padding-box;
|
||||
color: var(--efy_text2);
|
||||
border: 0 !important;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
48
src/components/CollapsableText.vue
Normal file
48
src/components/CollapsableText.vue
Normal file
@ -0,0 +1,48 @@
|
||||
<template v-if="text">
|
||||
<div class="whitespace-pre-wrap">
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<span v-if="showFullText" v-html="fullText()" />
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<span v-else v-html="colapsedText()" />
|
||||
<span v-if="text.length > 100 && !showFullText">...</span>
|
||||
<button
|
||||
v-if="text.length > 100"
|
||||
style="
|
||||
margin: 0 0 0 10rem;
|
||||
background: var(--efy_bg1);
|
||||
-webkit-text-fill-color: var(--efy_text);
|
||||
padding: 5rem 8reml;
|
||||
"
|
||||
class="efy_shadow_trans efy_shadow_button_off efy_button_text_off"
|
||||
@click="showFullText = !showFullText"
|
||||
>
|
||||
{{ showFullText ? $t("actions.show_less") : $t("actions.show_more") }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { purifyHTML, rewriteDescription } from "@/utils/HtmlUtils";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
text: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showFullText: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
fullText() {
|
||||
return purifyHTML(rewriteDescription(this.text));
|
||||
},
|
||||
colapsedText() {
|
||||
return purifyHTML(rewriteDescription(this.text.slice(0, 100)));
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
@ -1,38 +1,43 @@
|
||||
<template>
|
||||
<div class="comment flex mt-1.5">
|
||||
<img :src="comment.thumbnail" class="comment-avatar" height="48" width="48" loading="lazy" alt="Avatar" />
|
||||
<router-link style="height: fit-content" :to="comment.commentorUrl">
|
||||
<img :src="comment.thumbnail" class="comment-avatar" height="48" width="48" loading="lazy" alt="Avatar" />
|
||||
</router-link>
|
||||
|
||||
<div class="comment-content pl-2">
|
||||
<div class="comment-header">
|
||||
<div v-if="comment.pinned" class="comment-pinned">
|
||||
<font-awesome-icon icon="thumbtack" />
|
||||
<span
|
||||
class="ml-1.5"
|
||||
v-t="{
|
||||
path: 'comment.pinned_by',
|
||||
args: { author: uploader },
|
||||
}"
|
||||
class="ml-1.5"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="comment-author mt-1 flex">
|
||||
<router-link class="font-bold link" :to="comment.commentorUrl">{{ comment.author }}</router-link>
|
||||
<font-awesome-icon class="ml-1.5" v-if="comment.verified" icon="check" />
|
||||
<div class="comment-author flex align-center">
|
||||
<router-link class="link font-bold" :to="comment.commentorUrl">{{ comment.author }}</router-link>
|
||||
<font-awesome-icon v-if="comment.verified" class="ml-1.5" icon="check" />
|
||||
<div class="comment-meta mb-1.5" v-text="' • ' + comment.commentedTime + ' •'" />
|
||||
<div class="i-fa-solid:thumbs-up" />
|
||||
<span class="ml-1" v-text="numberFormat(comment.likeCount)" />
|
||||
<font-awesome-icon class="ml-1" v-if="comment.hearted" icon="heart" />
|
||||
<div class="comment-footer mt-1 flex items-center">
|
||||
<div class="i-fa6-solid:thumbs-up" />
|
||||
<span class="ml-1" v-text="numberFormat(comment.likeCount)" />
|
||||
<font-awesome-icon v-if="comment.hearted" class="ml-1" icon="heart" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="whitespace-pre-wrap" v-html="purifyHTML(comment.commentText)" />
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div class="whitespace-pre-wrap" v-html="purifiedText" />
|
||||
<template v-if="comment.repliesPage && (!loadingReplies || !showingReplies)">
|
||||
<div @click="loadReplies" class="cursor-pointer">
|
||||
<div class="cursor-pointer" @click="loadReplies">
|
||||
<a v-text="`${$t('actions.reply_count', comment.replyCount)}`" />
|
||||
<font-awesome-icon class="ml-1.5" icon="level-down-alt" />
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="showingReplies">
|
||||
<div @click="hideReplies" class="cursor-pointer">
|
||||
<div class="cursor-pointer" @click="hideReplies">
|
||||
<a v-t="'actions.hide_replies'" />
|
||||
<font-awesome-icon class="ml-1.5" icon="level-up-alt" />
|
||||
</div>
|
||||
@ -41,7 +46,7 @@
|
||||
<div v-for="reply in replies" :key="reply.commentId" class="w-full">
|
||||
<CommentItem :comment="reply" :uploader="uploader" :video-id="videoId" />
|
||||
</div>
|
||||
<div v-if="nextpage" @click="loadReplies" class="cursor-pointer">
|
||||
<div v-if="nextpage" class="cursor-pointer" @click="loadReplies">
|
||||
<a v-t="'actions.load_more_replies'" />
|
||||
<font-awesome-icon class="ml-1.5" icon="level-down-alt" />
|
||||
</div>
|
||||
@ -51,6 +56,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { purifyHTML } from "@/utils/HtmlUtils";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
comment: {
|
||||
@ -70,6 +77,11 @@ export default {
|
||||
nextpage: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
purifiedText() {
|
||||
return purifyHTML(this.comment.commentText);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async loadReplies() {
|
||||
if (!this.showingReplies && this.loadingReplies) {
|
||||
@ -97,4 +109,7 @@ export default {
|
||||
.comment-content {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.comment-avatar {
|
||||
max-width: unset;
|
||||
}
|
||||
</style>
|
||||
|
29
src/components/ConfirmModal.vue
Normal file
29
src/components/ConfirmModal.vue
Normal file
@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<ModalComponent @close="$emit('close')">
|
||||
<div>
|
||||
<h5 v-text="message" />
|
||||
<hr />
|
||||
<div class="w-min flex" style="gap: var(--efy_gap0)">
|
||||
<button v-t="'actions.cancel'" class="btn" @click="$emit('close')" />
|
||||
<button v-t="'actions.okay'" class="btn" @click="$emit('confirm')" />
|
||||
</div>
|
||||
</div>
|
||||
</ModalComponent>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ModalComponent from "./ModalComponent.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ModalComponent,
|
||||
},
|
||||
props: {
|
||||
message: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
emits: ["close", "confirm"],
|
||||
};
|
||||
</script>
|
@ -6,7 +6,10 @@
|
||||
import { defineAsyncComponent } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
item: Object,
|
||||
item: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const VideoItem = defineAsyncComponent(() => import("./VideoItem.vue"));
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<p v-text="message" />
|
||||
<button @click="toggleTrace" class="btn" v-t="'actions.show_more'" />
|
||||
<button v-t="'actions.show_more'" class="btn" @click="toggleTrace" />
|
||||
<p ref="stacktrace" class="whitespace-pre-wrap" hidden v-text="error" />
|
||||
</template>
|
||||
|
||||
|
@ -1,40 +1,97 @@
|
||||
<template>
|
||||
<button class="btn mr-2" @click="exportHandler">
|
||||
<router-link to="/subscriptions">Subscriptions</router-link>
|
||||
</button>
|
||||
|
||||
<span>
|
||||
<a :href="getRssUrl" class="btn">
|
||||
<font-awesome-icon icon="rss" />
|
||||
</a>
|
||||
</span>
|
||||
|
||||
<span class="md:float-right flex pp-sortby-feed">
|
||||
<SortingSelector by-key="uploaded" @apply="order => videos.sort(order)" />
|
||||
</span>
|
||||
|
||||
<hr />
|
||||
<div class="flex flex-wrap align-center" style="place-content: space-between; gap: var(--efy_gap0)">
|
||||
<span class="buttons flex" style="gap: var(--efy_gap0)">
|
||||
<router-link role="button" to="/subscriptions">Subscriptions</router-link>
|
||||
<a :href="getRssUrl" role="button" class="pp-square">
|
||||
<font-awesome-icon icon="rss" />
|
||||
</a>
|
||||
</span>
|
||||
|
||||
<div class="video-grid">
|
||||
<VideoItem :is-feed="true" v-for="video in videos" :key="video.url" :item="video" />
|
||||
<div class="filters flex align-center">
|
||||
<span class="flex">
|
||||
<label for="filters" v-text="`${$t('actions.filter')}:`" />
|
||||
<select
|
||||
id="filters"
|
||||
v-model="selectedFilter"
|
||||
default="all"
|
||||
class="select flex-grow"
|
||||
@change="onFilterChange()"
|
||||
>
|
||||
<option v-for="filter in availableFilters" :key="filter" v-t="`video.${filter}`" :value="filter" />
|
||||
</select>
|
||||
</span>
|
||||
|
||||
<span class="flex">
|
||||
<label for="group-selector" v-text="`${$t('titles.channel_groups')}:`" />
|
||||
<select id="group-selector" v-model="selectedGroupName" default="" class="select flex-grow">
|
||||
<option v-t="`video.all`" value="" />
|
||||
<option
|
||||
v-for="group in channelGroups"
|
||||
:key="group.groupName"
|
||||
:value="group.groupName"
|
||||
v-text="group.groupName"
|
||||
/>
|
||||
</select>
|
||||
</span>
|
||||
|
||||
<span class="pp-sortby-feed flex">
|
||||
<SortingSelector by-key="uploaded" @apply="order => videos.sort(order)" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<LoadingIndicatorPage :show-content="videosStore != null" class="video-grid">
|
||||
<template v-for="video in filteredVideos" :key="video.url">
|
||||
<VideoItem v-if="shouldShowVideo(video)" :is-feed="true" :item="video" />
|
||||
</template>
|
||||
</LoadingIndicatorPage>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.filters {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.filters,
|
||||
.filters span {
|
||||
gap: var(--efy_gap0);
|
||||
}
|
||||
.filters :is(select, label),
|
||||
.buttons a[role="button"] {
|
||||
margin: 0 !important;
|
||||
white-space: nowrap;
|
||||
align-items: center;
|
||||
place-content: center;
|
||||
}
|
||||
.filters span {
|
||||
align-items: center;
|
||||
}
|
||||
.buttons a[role="button"] {
|
||||
height: var(--efy_ratio_width);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import VideoItem from "./VideoItem.vue";
|
||||
import SortingSelector from "./SortingSelector.vue";
|
||||
import LoadingIndicatorPage from "./LoadingIndicatorPage.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VideoItem,
|
||||
SortingSelector,
|
||||
LoadingIndicatorPage,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentVideoCount: 0,
|
||||
videoStep: 100,
|
||||
videosStore: [],
|
||||
videosStore: null,
|
||||
videos: [],
|
||||
availableFilters: ["all", "shorts", "videos"],
|
||||
selectedFilter: "all",
|
||||
selectedGroupName: "",
|
||||
channelGroups: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -42,6 +99,12 @@ export default {
|
||||
if (_this.authenticated) return _this.authApiUrl() + "/feed/rss?authToken=" + _this.getAuthToken();
|
||||
else return _this.authApiUrl() + "/feed/unauthenticated/rss?channels=" + _this.getUnauthenticatedChannels();
|
||||
},
|
||||
filteredVideos(_this) {
|
||||
const selectedGroup = _this.channelGroups.filter(group => group.groupName == _this.selectedGroupName);
|
||||
return _this.selectedGroupName == ""
|
||||
? _this.videos
|
||||
: _this.videos.filter(video => selectedGroup[0].channels.includes(video.uploaderUrl.substr(-11)));
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetchFeed().then(videos => {
|
||||
@ -49,6 +112,23 @@ export default {
|
||||
this.loadMoreVideos();
|
||||
this.updateWatched(this.videos);
|
||||
});
|
||||
|
||||
this.selectedFilter = this.getPreferenceString("feedFilter") ?? "all";
|
||||
|
||||
if (!window.db) return;
|
||||
|
||||
const cursor = this.getChannelGroupsCursor();
|
||||
cursor.onsuccess = e => {
|
||||
const cursor = e.target.result;
|
||||
if (cursor) {
|
||||
const group = cursor.value;
|
||||
this.channelGroups.push({
|
||||
groupName: group.groupName,
|
||||
channels: JSON.parse(group.channels),
|
||||
});
|
||||
cursor.continue();
|
||||
}
|
||||
};
|
||||
},
|
||||
activated() {
|
||||
document.title = this.$t("titles.feed") + " - Piped";
|
||||
@ -74,15 +154,31 @@ export default {
|
||||
}
|
||||
},
|
||||
loadMoreVideos() {
|
||||
if (!this.videosStore) return;
|
||||
this.currentVideoCount = Math.min(this.currentVideoCount + this.videoStep, this.videosStore.length);
|
||||
if (this.videos.length != this.videosStore.length)
|
||||
if (this.videos.length != this.videosStore.length) {
|
||||
this.videos = this.videosStore.slice(0, this.currentVideoCount);
|
||||
this.fetchDeArrowContent(this.videos);
|
||||
}
|
||||
},
|
||||
handleScroll() {
|
||||
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - window.innerHeight) {
|
||||
this.loadMoreVideos();
|
||||
}
|
||||
},
|
||||
shouldShowVideo(video) {
|
||||
switch (this.selectedFilter.toLowerCase()) {
|
||||
case "shorts":
|
||||
return video.isShort;
|
||||
case "videos":
|
||||
return !video.isShort;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
},
|
||||
onFilterChange() {
|
||||
this.setPreference("feedFilter", this.selectedFilter);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<footer class="efy_trans_filter">
|
||||
<footer class="efy_trans_filter efy_shadow_trans efy_shadow_button_off">
|
||||
<a aria-label="GitHub" href="https://github.com/TeamPiped/Piped" target="_blank">
|
||||
<font-awesome-icon :icon="['fab', 'github']" />
|
||||
<span v-t="'actions.source_code'" />
|
||||
@ -58,12 +58,13 @@ footer {
|
||||
padding: 15rem 5rem;
|
||||
border: var(--efy_border);
|
||||
}
|
||||
footer > a {
|
||||
margin: 0;
|
||||
}
|
||||
footer a {
|
||||
color: var(--efy_text) !important;
|
||||
-webkit-text-fill-color: var(--efy_text) !important;
|
||||
background: transparent !important;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
gap: 8rem;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,13 +1,34 @@
|
||||
<template>
|
||||
<h1 class="font-bold text-center" v-t="'titles.history'" />
|
||||
|
||||
<div class="flex place-items-center">
|
||||
<div class="mr-2">
|
||||
<button class="btn" v-t="'actions.clear_history'" @click="clearHistory" />
|
||||
<hr />
|
||||
<div class="flex flex-wrap items-center place-content-between" style="gap: var(--efy_gap0)">
|
||||
<div class="flex" style="gap: var(--efy_gap0)">
|
||||
<button v-t="'actions.clear_history'" class="m-0" @click="clearHistory" />
|
||||
<button v-t="'actions.export_to_json'" class="m-0" @click="exportHistory" />
|
||||
</div>
|
||||
|
||||
<div class="mr-2">
|
||||
<SortingSelector by-key="watchedAt" @apply="order => videos.sort(order)" />
|
||||
<div class="flex flex-wrap items-center" style="gap: var(--efy_gap0)">
|
||||
<div efy_select class="flex flex-wrap" style="gap: var(--efy_gap0)">
|
||||
<input id="autoDelete" v-model="autoDeleteHistory" type="checkbox" @change="onChange" />
|
||||
<label v-t="'actions.delete_automatically'" style="margin: 0" for="autoDelete" />
|
||||
<select
|
||||
v-model="autoDeleteDelayHours"
|
||||
class="w-auto"
|
||||
style="margin: 0 var(--efy_gap0) 0 0"
|
||||
@change="onChange"
|
||||
>
|
||||
<option v-t="{ path: 'info.hours', args: { amount: '1' } }" value="1" />
|
||||
<option v-t="{ path: 'info.hours', args: { amount: '3' } }" value="3" />
|
||||
<option v-t="{ path: 'info.hours', args: { amount: '6' } }" value="6" />
|
||||
<option v-t="{ path: 'info.hours', args: { amount: '12' } }" value="12" />
|
||||
<option v-t="{ path: 'info.days', args: { amount: '1' } }" value="24" />
|
||||
<option v-t="{ path: 'info.days', args: { amount: '3' } }" value="72" />
|
||||
<option v-t="{ path: 'info.weeks', args: { amount: '1' } }" value="168" />
|
||||
<option v-t="{ path: 'info.weeks', args: { amount: '3' } }" value="336" />
|
||||
<option v-t="{ path: 'info.months', args: { amount: '1' } }" value="672" />
|
||||
<option v-t="{ path: 'info.months', args: { amount: '2' } }" value="1344" />
|
||||
</select>
|
||||
</div>
|
||||
<SortingSelector by-key="watchedAt" @apply="order => videos.sort(order)" style="gap: 0" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -16,8 +37,6 @@
|
||||
<div class="video-grid">
|
||||
<VideoItem v-for="video in videos" :key="video.url" :item="video" />
|
||||
</div>
|
||||
|
||||
<br />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -32,28 +51,39 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
videos: [],
|
||||
autoDeleteHistory: false,
|
||||
autoDeleteDelayHours: "24",
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.autoDeleteHistory = this.getPreferenceBoolean("autoDeleteWatchHistory", false);
|
||||
this.autoDeleteDelayHours = this.getPreferenceString("autoDeleteWatchHistoryDelayHours", "24");
|
||||
|
||||
(async () => {
|
||||
if (window.db) {
|
||||
var tx = window.db.transaction("watch_history", "readonly");
|
||||
if (window.db && this.getPreferenceBoolean("watchHistory", false)) {
|
||||
var tx = window.db.transaction("watch_history", "readwrite");
|
||||
var store = tx.objectStore("watch_history");
|
||||
const cursorRequest = store.index("watchedAt").openCursor(null, "prev");
|
||||
cursorRequest.onsuccess = e => {
|
||||
const cursor = e.target.result;
|
||||
if (cursor) {
|
||||
const video = cursor.value;
|
||||
this.videos.push({
|
||||
url: "/watch?v=" + video.videoId,
|
||||
title: video.title,
|
||||
uploaderName: video.uploaderName,
|
||||
uploaderUrl: video.uploaderUrl,
|
||||
duration: video.duration,
|
||||
thumbnail: video.thumbnail,
|
||||
watchedAt: video.watchedAt,
|
||||
});
|
||||
if (this.videos.length < 1000) cursor.continue();
|
||||
if (!this.shouldRemoveVideo(video)) {
|
||||
this.videos.push({
|
||||
url: "/watch?v=" + video.videoId,
|
||||
title: video.title,
|
||||
uploaderName: video.uploaderName,
|
||||
uploaderUrl: video.uploaderUrl,
|
||||
duration: video.duration,
|
||||
thumbnail: video.thumbnail,
|
||||
watchedAt: video.watchedAt,
|
||||
watched: true,
|
||||
currentTime: video.currentTime,
|
||||
});
|
||||
} else {
|
||||
store.delete(video.videoId);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -71,6 +101,32 @@ export default {
|
||||
}
|
||||
this.videos = [];
|
||||
},
|
||||
exportHistory() {
|
||||
const dateStr = new Date().toISOString().split(".")[0];
|
||||
let json = {
|
||||
format: "Piped",
|
||||
version: 1,
|
||||
playlists: [
|
||||
{
|
||||
name: `Piped History ${dateStr}`,
|
||||
type: "history",
|
||||
visibility: "private",
|
||||
videos: this.videos.map(video => "https://youtube.com" + video.url),
|
||||
},
|
||||
],
|
||||
};
|
||||
this.download(JSON.stringify(json), `piped_history_${dateStr}.json`, "application/json");
|
||||
},
|
||||
onChange() {
|
||||
this.setPreference("autoDeleteWatchHistory", this.autoDeleteHistory);
|
||||
this.setPreference("autoDeleteWatchHistoryDelayHours", this.autoDeleteDelayHours);
|
||||
},
|
||||
shouldRemoveVideo(video) {
|
||||
if (!this.autoDeleteHistory) return false;
|
||||
// convert from hours to milliseconds
|
||||
let maximumTimeDiff = Number(this.autoDeleteDelayHours) * 60 * 60 * 1000;
|
||||
return Date.now() - video.watchedAt > maximumTimeDiff;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<hr />
|
||||
<div>
|
||||
<form style="display: grid; gap: 15rem">
|
||||
<div>
|
||||
@ -11,9 +12,7 @@
|
||||
<input v-model="override" id="import-override" type="checkbox" />
|
||||
<label for="import-override">Override</label>
|
||||
</div>
|
||||
<div>
|
||||
<a class="btn w-auto" @click="handleImport">Import</a>
|
||||
</div>
|
||||
<a class="btn w-auto" @click="handleImport" role="button" style="margin: 0">Import</a>
|
||||
</form>
|
||||
<br />
|
||||
<strong>Importing Subscriptions from YouTube</strong>
|
||||
@ -106,10 +105,14 @@ export default {
|
||||
}
|
||||
// FreeTube DB
|
||||
else if (text.indexOf("allChannels") != -1) {
|
||||
const json = JSON.parse(text);
|
||||
json.subscriptions.forEach(item => {
|
||||
this.subscriptions.push(item.id);
|
||||
});
|
||||
const lines = text.split("\n");
|
||||
for (let line of lines) {
|
||||
if (line === "") continue;
|
||||
const json = JSON.parse(line);
|
||||
json.subscriptions.forEach(item => {
|
||||
this.subscriptions.push(item.id);
|
||||
});
|
||||
}
|
||||
}
|
||||
// Google Takeout JSON
|
||||
else if (text.indexOf("contentDetails") != -1) {
|
||||
|
47
src/components/LoadingIndicatorPage.vue
Normal file
47
src/components/LoadingIndicatorPage.vue
Normal file
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div v-if="!showContent" class="min-h-[75vh] min-w-[75vw] w-full flex items-center justify-center">
|
||||
<span id="spinner" />
|
||||
</div>
|
||||
<div v-else>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
showContent: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#spinner {
|
||||
display: inline-block;
|
||||
width: 70rem;
|
||||
height: 70rem;
|
||||
}
|
||||
#spinner:after {
|
||||
content: " ";
|
||||
display: block;
|
||||
width: 54rem;
|
||||
height: 54rem;
|
||||
margin: 8rem;
|
||||
border-radius: 50%;
|
||||
border: 4rem solid var(--efy_text);
|
||||
border-color: var(--efy_text) transparent var(--efy_text) transparent;
|
||||
animation: spinner 1.2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spinner {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<ModalComponent>
|
||||
<h3 v-t="'titles.account'" class="font-bold my-4" />
|
||||
<h5 v-t="'titles.account'" class="font-bold my-4" />
|
||||
<hr />
|
||||
<div class="text-center">
|
||||
<form class="children:pb-3">
|
||||
<div>
|
||||
<input
|
||||
v-model="username"
|
||||
class="input w-full"
|
||||
class="m-0"
|
||||
type="text"
|
||||
autocomplete="username"
|
||||
:placeholder="$t('login.username')"
|
||||
@ -18,7 +18,7 @@
|
||||
<div>
|
||||
<input
|
||||
v-model="password"
|
||||
class="input w-full"
|
||||
class="m-0"
|
||||
type="password"
|
||||
autocomplete="password"
|
||||
:placeholder="$t('login.password')"
|
||||
@ -26,9 +26,9 @@
|
||||
v-on:keyup.enter="login"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<a class="btn mr-2 cursor-pointer" @click="register" v-t="'titles.register'" />
|
||||
<a class="btn cursor-pointer" @click="login" v-t="'titles.login'" />
|
||||
<div class="flex justify-end p-0!" style="gap: var(--efy_gap0)">
|
||||
<a role="button" class="m-0!" @click="register" v-t="'titles.register'" />
|
||||
<a role="button" class="m-0!" @click="login" v-t="'titles.login'" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
70
src/components/LoginPage.vue
Normal file
70
src/components/LoginPage.vue
Normal file
@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<h1 v-t="'titles.login'" class="my-4 text-center font-bold" />
|
||||
<hr />
|
||||
<div class="text-center">
|
||||
<form class="children:pb-3">
|
||||
<div>
|
||||
<input
|
||||
v-model="username"
|
||||
class="input"
|
||||
type="text"
|
||||
autocomplete="username"
|
||||
:placeholder="$t('login.username')"
|
||||
:aria-label="$t('login.username')"
|
||||
@keyup.enter="login"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
v-model="password"
|
||||
class="input"
|
||||
type="password"
|
||||
autocomplete="password"
|
||||
:placeholder="$t('login.password')"
|
||||
:aria-label="$t('login.password')"
|
||||
@keyup.enter="login"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<a v-t="'titles.login'" class="btn w-auto" @click="login" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
username: null,
|
||||
password: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
//TODO: Add Server Side check
|
||||
if (this.getAuthToken()) {
|
||||
this.$router.push("/");
|
||||
}
|
||||
},
|
||||
activated() {
|
||||
document.title = this.$t("titles.login") + " - Piped";
|
||||
},
|
||||
methods: {
|
||||
login() {
|
||||
if (!this.username || !this.password) return;
|
||||
this.fetchJson(this.authApiUrl() + "/login", null, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
username: this.username,
|
||||
password: this.password,
|
||||
}),
|
||||
}).then(resp => {
|
||||
if (resp.token) {
|
||||
this.setPreference("authToken" + this.hashCode(this.authApiUrl()), resp.token);
|
||||
window.location = "/"; // done to bypass cache
|
||||
} else alert(resp.error);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
@ -2,7 +2,9 @@
|
||||
<div class="modal">
|
||||
<div @click="handleClick">
|
||||
<div class="modal-container">
|
||||
<button @click="$emit('close')"><font-awesome-icon icon="xmark" /></button>
|
||||
<button @click="$emit('close')" class="pp-color btn m-0">
|
||||
<font-awesome-icon icon="xmark" />
|
||||
</button>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
@ -11,6 +13,7 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
emits: ["close"],
|
||||
mounted() {
|
||||
window.addEventListener("keydown", this.handleKeyDown);
|
||||
},
|
||||
@ -36,16 +39,13 @@ export default {
|
||||
.modal {
|
||||
@apply fixed z-50 top-0 left-0 w-full h-full bg-dark-900 bg-opacity-80 transition-opacity table;
|
||||
}
|
||||
|
||||
.modal > div {
|
||||
@apply table-cell align-middle;
|
||||
}
|
||||
|
||||
.modal-container {
|
||||
@apply w-300rem m-auto max-w-[100vw] relative;
|
||||
@apply w-100% m-auto max-w-[421rem] relative;
|
||||
}
|
||||
|
||||
.modal-container > button {
|
||||
@apply absolute right-50 top-30;
|
||||
@apply absolute right-[12rem] top-[15rem];
|
||||
}
|
||||
</style>
|
||||
|
@ -56,10 +56,10 @@
|
||||
</div>
|
||||
<div class="lt-md:hidden flex flex-1 justify-start" style="position: relative">
|
||||
<input
|
||||
ref="videoSearch"
|
||||
v-model="searchText"
|
||||
type="text"
|
||||
role="search"
|
||||
ref="videoSearch"
|
||||
:title="$t('actions.search')"
|
||||
:placeholder="$t('actions.search')"
|
||||
@keyup="onKeyUp"
|
||||
@ -78,8 +78,8 @@
|
||||
<router-link v-t="'titles.preferences'" to="/preferences" />
|
||||
<p
|
||||
v-if="shouldShowLogin"
|
||||
class="cursor-pointer font-bold"
|
||||
v-t="'titles.account'"
|
||||
class="cursor-pointer font-bold"
|
||||
@click="showLoginModal = !showLoginModal"
|
||||
/>
|
||||
<router-link v-if="shouldShowHistory" v-t="'titles.history'" to="/history" />
|
||||
@ -87,15 +87,8 @@
|
||||
<router-link v-if="!shouldShowTrending" v-t="'titles.feed'" to="/feed" />
|
||||
<button
|
||||
efy_sidebar_btn="relative, pp-desktop"
|
||||
style="
|
||||
background: transparent;
|
||||
-webkit-text-fill-color: var(--efy_text);
|
||||
padding: 0;
|
||||
margin: -5rem 0 0 0;
|
||||
border: 0;
|
||||
backdrop-filter: none !important;
|
||||
-webkit-backdrop-filter: none !important;
|
||||
"
|
||||
style="background: transparent; padding: 0; margin: -5rem 0 0 0; border: 0"
|
||||
class="efy_trans_filter_off efy_shadow_button_off"
|
||||
>
|
||||
<i efy_icon="menu" style="margin: 0" />
|
||||
</button>
|
||||
@ -103,7 +96,7 @@
|
||||
</nav>
|
||||
|
||||
<!-- search suggestions for mobile devices -->
|
||||
<div class="w-{full - 4} md:hidden mx-2" style="position: relative">
|
||||
<div class="w-{full - 4} md:hidden" style="position: relative">
|
||||
<input
|
||||
v-model="searchText"
|
||||
type="text"
|
||||
@ -114,8 +107,9 @@
|
||||
@keypress="onKeyPress"
|
||||
@focus="onInputFocus"
|
||||
@blur="onInputBlur"
|
||||
style="margin: 15rem 0 0 0"
|
||||
/>
|
||||
<span v-if="searchText" class="delete-search" @click="searchText = ''">x</span>
|
||||
<span v-if="searchText" class="delete-search" @click="searchText = ''">⨉</span>
|
||||
</div>
|
||||
<SearchSuggestions
|
||||
v-show="(searchText || showSearchHistory) && suggestionsVisible"
|
||||
@ -128,13 +122,13 @@
|
||||
|
||||
<style>
|
||||
.pp-nav {
|
||||
margin-bottom: 15rem;
|
||||
gap: 15rem;
|
||||
}
|
||||
.pp-nav > .pp-logo > a {
|
||||
font-size: 25rem;
|
||||
font-family: "nunito";
|
||||
background: transparent;
|
||||
margin-left: 5rem;
|
||||
}
|
||||
.pp-nav > div input {
|
||||
margin: 0 !important;
|
||||
@ -204,17 +198,17 @@ export default {
|
||||
suggestionsVisible: false,
|
||||
showLoginModal: false,
|
||||
showTopNav: false,
|
||||
homePagePath: "/",
|
||||
registrationDisabled: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
const query = new URLSearchParams(window.location.search).get("search_query");
|
||||
if (query) this.onSearchTextChange(query);
|
||||
this.focusOnSearchBar();
|
||||
},
|
||||
computed: {
|
||||
shouldShowLogin(_this) {
|
||||
return _this.getAuthToken() == null;
|
||||
},
|
||||
shouldShowRegister(_this) {
|
||||
return _this.registrationDisabled == false ? _this.shouldShowLogin : false;
|
||||
},
|
||||
shouldShowHistory(_this) {
|
||||
return _this.getPreferenceBoolean("watchHistory", false);
|
||||
},
|
||||
@ -225,6 +219,13 @@ export default {
|
||||
return _this.getPreferenceBoolean("searchHistory", false) && localStorage.getItem("search_history");
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetchAuthConfig();
|
||||
const query = new URLSearchParams(window.location.search).get("search_query");
|
||||
if (query) this.onSearchTextChange(query);
|
||||
this.focusOnSearchBar();
|
||||
this.homePagePath = this.getHomePage(this);
|
||||
},
|
||||
methods: {
|
||||
// focus on search bar when Ctrl+k is pressed
|
||||
focusOnSearchBar() {
|
||||
@ -241,12 +242,7 @@ export default {
|
||||
},
|
||||
onKeyPress(e) {
|
||||
if (e.key === "Enter") {
|
||||
e.target.blur();
|
||||
this.$router.push({
|
||||
name: "SearchResults",
|
||||
query: { search_query: this.searchText },
|
||||
});
|
||||
return;
|
||||
this.submitSearch(e);
|
||||
}
|
||||
},
|
||||
onInputFocus() {
|
||||
@ -259,6 +255,22 @@ export default {
|
||||
onSearchTextChange(searchText) {
|
||||
this.searchText = searchText;
|
||||
},
|
||||
async fetchAuthConfig() {
|
||||
this.fetchJson(this.authApiUrl() + "/config").then(config => {
|
||||
this.registrationDisabled = config?.registrationDisabled === true;
|
||||
});
|
||||
},
|
||||
onSearchClick(e) {
|
||||
this.submitSearch(e);
|
||||
},
|
||||
submitSearch(e) {
|
||||
e.target.blur();
|
||||
this.$router.push({
|
||||
name: "SearchResults",
|
||||
query: { search_query: this.searchText },
|
||||
});
|
||||
return;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="flex flex-col justify-center items-center min-h-[88vh]">
|
||||
<h1 class="font-bold !text-[170rem] mb-[-6vh]">404</h1>
|
||||
<h2 class="!text-[40rem]" v-t="'info.page_not_found'" />
|
||||
<a class="btn mt-128" href="/" v-t="'actions.back_to_home'" />
|
||||
<h2 v-t="'info.page_not_found'" class="!text-[40rem]" />
|
||||
<a v-t="'actions.back_to_home'" role="button" href="/" />
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,15 +1,16 @@
|
||||
<template>
|
||||
<ModalComponent>
|
||||
<ModalComponent @close="$emit('close')">
|
||||
<h4 v-t="'actions.select_playlist'" class="mb-2" />
|
||||
<select class="select w-full mb-2" v-model="selectedPlaylist">
|
||||
<option v-for="playlist in playlists" :value="playlist.id" :key="playlist.id" v-text="playlist.name" />
|
||||
<select v-model="selectedPlaylist" class="select w-full mb-2">
|
||||
<option v-for="playlist in playlists" :key="playlist.id" :value="playlist.id" v-text="playlist.name" />
|
||||
</select>
|
||||
<div class="flex justify-end">
|
||||
<div class="flex justify-end" style="gap: var(--efy_gap0)">
|
||||
<button ref="addButton" v-t="'actions.create_playlist'" class="btn pp-color" @click="onCreatePlaylist" />
|
||||
<button
|
||||
class="btn"
|
||||
@click="handleClick(selectedPlaylist)"
|
||||
ref="addButton"
|
||||
v-t="'actions.add_to_playlist'"
|
||||
class="btn pp-color"
|
||||
@click="handleClick(selectedPlaylist)"
|
||||
/>
|
||||
</div>
|
||||
</ModalComponent>
|
||||
@ -23,11 +24,16 @@ export default {
|
||||
ModalComponent,
|
||||
},
|
||||
props: {
|
||||
videoInfo: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
videoId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
emits: ["close"],
|
||||
data() {
|
||||
return {
|
||||
playlists: [],
|
||||
@ -62,31 +68,25 @@ export default {
|
||||
this.$refs.addButton.disabled = true;
|
||||
this.processing = true;
|
||||
|
||||
this.fetchJson(this.authApiUrl() + "/user/playlists/add", null, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
playlistId: playlistId,
|
||||
videoId: this.videoId,
|
||||
}),
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}).then(json => {
|
||||
this.addVideosToPlaylist(playlistId, [this.videoId], [this.videoInfo]).then(json => {
|
||||
this.setPreference("selectedPlaylist" + this.hashCode(this.authApiUrl()), playlistId);
|
||||
this.$emit("close");
|
||||
if (json.error) alert(json.error);
|
||||
});
|
||||
},
|
||||
async fetchPlaylists() {
|
||||
this.fetchJson(this.authApiUrl() + "/user/playlists", null, {
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
},
|
||||
}).then(json => {
|
||||
this.getPlaylists().then(json => {
|
||||
this.playlists = json;
|
||||
});
|
||||
},
|
||||
onCreatePlaylist() {
|
||||
const name = prompt(this.$t("actions.create_playlist"));
|
||||
if (!name) return;
|
||||
this.createPlaylist(name).then(json => {
|
||||
if (json.error) alert(json.error);
|
||||
else this.fetchPlaylists();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -1,34 +1,47 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="video-card flex flex-col flex-justify-between efy_shadow_trans">
|
||||
<router-link :to="props.item.url">
|
||||
<div class="relative">
|
||||
<img class="w-full" :src="props.item.thumbnail" loading="lazy" />
|
||||
<img class="thumbnail" :src="props.item.thumbnail" loading="lazy" />
|
||||
</div>
|
||||
<div class="flex items-center h-[44rem] overflow-hidden">
|
||||
<p v-text="props.item.name" class="pp-video-card-title" />
|
||||
</div>
|
||||
<p>
|
||||
<span v-text="props.item.name" />
|
||||
<font-awesome-icon class="ml-1.5" v-if="props.item.verified" icon="check" />
|
||||
</p>
|
||||
</router-link>
|
||||
<p v-if="props.item.description" v-text="props.item.description" />
|
||||
<router-link v-if="props.item.uploaderUrl" class="link" :to="props.item.uploaderUrl">
|
||||
<p>
|
||||
<span v-text="props.item.uploader" />
|
||||
<font-awesome-icon class="ml-1.5" v-if="props.item.uploaderVerified" icon="check" />
|
||||
</p>
|
||||
</router-link>
|
||||
|
||||
<a v-if="props.item.uploaderName" class="link" v-text="props.item.uploaderName" />
|
||||
<template v-if="props.item.videos >= 0">
|
||||
<br v-if="props.item.uploaderName" />
|
||||
<strong v-text="`${props.item.videos} ${$t('video.videos')}`" />
|
||||
</template>
|
||||
|
||||
<br />
|
||||
<div class="pp-video-card-buttons">
|
||||
<button
|
||||
v-if="props.item.videos >= 0"
|
||||
v-text="`${props.item.videos} ${$t('video.videos')}`"
|
||||
class="efy_shadow_trans efy_shadow_button_off efy_button_text_off"
|
||||
/>
|
||||
<router-link
|
||||
v-if="props.item.uploaderUrl && item.uploaderName"
|
||||
:to="props.item.uploaderUrl"
|
||||
:title="props.item.uploaderName"
|
||||
class="pp-video-card-channel"
|
||||
style="padding: 0; flex-grow: 1; background: transparent; border: 0"
|
||||
>
|
||||
<div class="pp-text efy_shadow_trans efy_shadow_button_off flex-grow-1">
|
||||
<span v-text="props.item.uploaderName" style="max-width: 106rem" />
|
||||
<font-awesome-icon class="ml-1.5" v-if="item.uploaderVerified" icon="check" />
|
||||
</div>
|
||||
</router-link>
|
||||
<a
|
||||
v-else-if="props.item.uploaderName"
|
||||
class="pp-video-card-channel efy_shadow_trans"
|
||||
v-text="props.item.uploaderName"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
item: Object,
|
||||
item: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
@ -1,29 +1,53 @@
|
||||
<template>
|
||||
<ErrorHandler v-if="playlist && playlist.error" :message="playlist.message" :error="playlist.error" />
|
||||
|
||||
<div v-if="playlist" v-show="!playlist.error">
|
||||
<h1 class="text-center my-4" v-text="playlist.name" />
|
||||
<LoadingIndicatorPage v-show="!playlist?.error" :show-content="playlist">
|
||||
<hr />
|
||||
<h5 class="mb-[10rem]" v-text="playlist.name" />
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<router-link class="link" :to="playlist.uploaderUrl || '/'">
|
||||
<img :src="playlist.uploaderAvatar" loading="lazy" />
|
||||
<strong v-text="playlist.uploader" />
|
||||
<CollapsableText v-if="playlist?.description" :text="playlist.description" />
|
||||
<hr />
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="pp-video-card-buttons m-0!">
|
||||
<router-link
|
||||
:to="playlist.uploaderUrl || '/'"
|
||||
class="pp-video-card-channel p-0!"
|
||||
style="background: transparent; border: 0"
|
||||
>
|
||||
<img
|
||||
v-if="playlist.uploaderAvatar"
|
||||
:src="playlist.uploaderAvatar"
|
||||
loading="lazy"
|
||||
width="36"
|
||||
height="36"
|
||||
class="w-36rem h-36rem efy_shadow_trans"
|
||||
/>
|
||||
<button class="pp-text efy_shadow_trans efy_shadow_button_off efy_button_text_off">
|
||||
<span v-text="playlist.uploader" />
|
||||
<font-awesome-icon class="ml-1.5" v-if="playlist.uploaderVerified" icon="check" />
|
||||
</button>
|
||||
</router-link>
|
||||
<button
|
||||
v-text="`${playlist.videos} ${$t('video.videos')}`"
|
||||
class="efy_button_text_off efy_shadow_trans efy_shadow_button_off"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<strong v-text="`${playlist.videos} ${$t('video.videos')}`" />
|
||||
<br />
|
||||
<button class="btn mr-1 ml-2" v-if="authenticated && !isPipedPlaylist" @click="clonePlaylist">
|
||||
{{ $t("actions.clone_playlist") }}<font-awesome-icon class="ml-3" icon="clone" />
|
||||
<div class="pp-flex-bookmarks">
|
||||
<button v-if="!isPipedPlaylist" class="btn" @click="bookmarkPlaylist">
|
||||
<font-awesome-icon class="mr-[5rem]" icon="bookmark" />
|
||||
{{ $t(`actions.${isBookmarked ? "playlist_bookmarked" : "bookmark_playlist"}`) }}
|
||||
</button>
|
||||
<button v-if="authenticated && !isPipedPlaylist" class="btn mr-1 ml-2" @click="clonePlaylist">
|
||||
<font-awesome-icon class="mr-[5rem]" icon="clone" />{{ $t("actions.clone_playlist") }}
|
||||
</button>
|
||||
<button class="btn mr-1" @click="downloadPlaylistAsTxt">
|
||||
{{ $t("actions.download_as_txt") }}
|
||||
</button>
|
||||
<a class="btn" :href="getRssUrl">
|
||||
<a :href="getRssUrl" role="button" class="btn pp-square">
|
||||
<font-awesome-icon icon="rss" />
|
||||
</a>
|
||||
<WatchOnYouTubeButton :link="`https://www.youtube.com/playlist?list=${this.$route.query.list}`" />
|
||||
<WatchOnButton :link="`https://www.youtube.com/playlist?list=${$route.query.list}`" class="pp-square" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -37,29 +61,45 @@
|
||||
:index="index"
|
||||
:playlist-id="$route.query.list"
|
||||
:admin="admin"
|
||||
@remove="removeVideo(index)"
|
||||
height="94"
|
||||
width="168"
|
||||
@remove="removeVideo(index)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</LoadingIndicatorPage>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.pp-flex-bookmarks {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--efy_gap0);
|
||||
}
|
||||
.pp-flex-bookmarks > * {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import ErrorHandler from "./ErrorHandler.vue";
|
||||
import LoadingIndicatorPage from "./LoadingIndicatorPage.vue";
|
||||
import CollapsableText from "./CollapsableText.vue";
|
||||
import VideoItem from "./VideoItem.vue";
|
||||
import WatchOnYouTubeButton from "./WatchOnYouTubeButton.vue";
|
||||
import WatchOnButton from "./WatchOnButton.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ErrorHandler,
|
||||
VideoItem,
|
||||
WatchOnYouTubeButton,
|
||||
WatchOnButton,
|
||||
LoadingIndicatorPage,
|
||||
CollapsableText,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
playlist: null,
|
||||
admin: false,
|
||||
isBookmarked: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -74,19 +114,17 @@ export default {
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getPlaylistData();
|
||||
const playlistId = this.$route.query.list;
|
||||
if (this.authenticated && playlistId?.length == 36)
|
||||
this.fetchJson(this.authApiUrl() + "/user/playlists", null, {
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
},
|
||||
}).then(json => {
|
||||
this.getPlaylists().then(json => {
|
||||
if (json.error) alert(json.error);
|
||||
else if (json.filter(playlist => playlist.id === playlistId).length > 0) this.admin = true;
|
||||
else if (json.some(playlist => playlist.id === playlistId)) this.admin = true;
|
||||
});
|
||||
else if (playlistId.startsWith("local")) this.admin = true;
|
||||
this.isPlaylistBookmarked();
|
||||
},
|
||||
activated() {
|
||||
this.getPlaylistData();
|
||||
window.addEventListener("scroll", this.handleScroll);
|
||||
if (this.playlist) this.updateTitle();
|
||||
},
|
||||
@ -95,12 +133,21 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async fetchPlaylist() {
|
||||
const playlistId = this.$route.query.list;
|
||||
if (playlistId.startsWith("local")) {
|
||||
return this.getPlaylist(playlistId);
|
||||
}
|
||||
|
||||
return await await this.fetchJson(this.authApiUrl() + "/playlists/" + this.$route.query.list);
|
||||
},
|
||||
async getPlaylistData() {
|
||||
this.fetchPlaylist()
|
||||
.then(data => (this.playlist = data))
|
||||
.then(() => this.updateTitle());
|
||||
.then(() => {
|
||||
this.updateTitle();
|
||||
this.updateWatched(this.playlist.relatedStreams);
|
||||
this.fetchDeArrowContent(this.playlist.relatedStreams);
|
||||
});
|
||||
},
|
||||
async updateTitle() {
|
||||
document.title = this.playlist.name + " - Piped";
|
||||
@ -116,6 +163,7 @@ export default {
|
||||
this.playlist.nextpage = json.nextpage;
|
||||
this.loading = false;
|
||||
json.relatedStreams.map(stream => this.playlist.relatedStreams.push(stream));
|
||||
this.fetchDeArrowContent(this.playlist.relatedStreams);
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -144,6 +192,48 @@ export default {
|
||||
});
|
||||
this.download(data, this.playlist.name + ".txt", "text/plain");
|
||||
},
|
||||
async bookmarkPlaylist() {
|
||||
if (!this.playlist) return;
|
||||
|
||||
if (this.isBookmarked) {
|
||||
this.removePlaylistBookmark();
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.db) {
|
||||
const playlistId = this.$route.query.list;
|
||||
var tx = window.db.transaction("playlist_bookmarks", "readwrite");
|
||||
var store = tx.objectStore("playlist_bookmarks");
|
||||
store.put({
|
||||
playlistId: playlistId,
|
||||
name: this.playlist.name,
|
||||
uploader: this.playlist.uploader,
|
||||
uploaderUrl: this.playlist.uploaderUrl,
|
||||
thumbnail: this.playlist.thumbnailUrl,
|
||||
uploaderAvatar: this.playlist.uploaderAvatar,
|
||||
videos: this.playlist.videos,
|
||||
});
|
||||
this.isBookmarked = true;
|
||||
}
|
||||
},
|
||||
async removePlaylistBookmark() {
|
||||
var tx = window.db.transaction("playlist_bookmarks", "readwrite");
|
||||
var store = tx.objectStore("playlist_bookmarks");
|
||||
store.delete(this.$route.query.list);
|
||||
this.isBookmarked = false;
|
||||
},
|
||||
async isPlaylistBookmarked() {
|
||||
// needed in order to change the is bookmarked var later
|
||||
const App = this;
|
||||
const playlistId = this.$route.query.list;
|
||||
var tx = window.db.transaction("playlist_bookmarks", "readwrite");
|
||||
var store = tx.objectStore("playlist_bookmarks");
|
||||
var req = store.openCursor(playlistId);
|
||||
req.onsuccess = function (e) {
|
||||
var cursor = e.target.result;
|
||||
App.isBookmarked = cursor ? true : false;
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -29,18 +29,7 @@ export default {
|
||||
},
|
||||
selectedIndex: {
|
||||
type: Number,
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.updateScroll();
|
||||
},
|
||||
methods: {
|
||||
updateScroll() {
|
||||
const elems = Array.from(this.$refs.scrollable.children).filter(elm => elm.matches("div"));
|
||||
const index = this.selectedIndex - 1;
|
||||
if (index < elems.length)
|
||||
this.$refs.scrollable.scrollTop =
|
||||
elems[this.selectedIndex - 1].offsetTop - this.$refs.scrollable.offsetTop;
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
@ -54,5 +43,18 @@ export default {
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.updateScroll();
|
||||
this.updateWatched(this.playlist.relatedStreams);
|
||||
},
|
||||
methods: {
|
||||
updateScroll() {
|
||||
const elems = Array.from(this.$refs.scrollable.children).filter(elm => elm.matches("div"));
|
||||
const index = this.selectedIndex - 1;
|
||||
if (index < elems.length)
|
||||
this.$refs.scrollable.scrollTop =
|
||||
elems[this.selectedIndex - 1].offsetTop - this.$refs.scrollable.offsetTop;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -1,125 +1,176 @@
|
||||
<template>
|
||||
<h1 class="font-bold text-center my-4" v-t="'titles.playlists'" />
|
||||
|
||||
<hr />
|
||||
<div class="flex flex-wrap justify-between items-center" style="gap: var(--efy_gap0)">
|
||||
<button
|
||||
v-t="'actions.create_playlist'"
|
||||
style="height: var(--efy_ratio_width); margin: 0"
|
||||
@click="onCreatePlaylist"
|
||||
/>
|
||||
<div class="flex flex-wrap" style="gap: var(--efy_gap0)">
|
||||
<button
|
||||
v-if="playlists.length > 0"
|
||||
v-t="'actions.export_to_json'"
|
||||
@click="exportPlaylists"
|
||||
style="height: var(--efy_ratio_width); margin: 0"
|
||||
/>
|
||||
<input
|
||||
id="fileSelector"
|
||||
ref="fileSelector"
|
||||
type="file"
|
||||
class="display-none"
|
||||
multiple="multiple"
|
||||
@change="importPlaylists"
|
||||
/>
|
||||
<label v-t="'actions.import_from_json_csv'" for="fileSelector" class="m-0! font-bold" role="button" />
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<div>
|
||||
<div class="flex justify-between">
|
||||
<button v-t="'actions.create_playlist'" class="btn mr-2" @click="onCreatePlaylist" />
|
||||
<div class="flex">
|
||||
<div class="video-grid">
|
||||
<div v-for="playlist in playlists" :key="playlist.id" class="video-card efy_trans_filter efy_shadow_trans">
|
||||
<router-link :to="`/playlist?list=${playlist.id}`">
|
||||
<img class="thumbnail" :src="playlist.thumbnail" alt="thumbnail" />
|
||||
<p
|
||||
style="display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; margin: 0 15rem"
|
||||
class="flex link"
|
||||
:title="playlist.name"
|
||||
v-text="playlist.name"
|
||||
/>
|
||||
</router-link>
|
||||
<div class="pp-video-card-buttons flex gap-15rem children:m-0" style="flex-wrap: wrap">
|
||||
<button
|
||||
v-if="this.playlists.length > 0"
|
||||
v-t="'actions.export_to_json'"
|
||||
class="btn"
|
||||
@click="exportPlaylists"
|
||||
v-text="`${playlist.videos} ${$t('video.videos')}`"
|
||||
class="efy_shadow_trans efy_shadow_button_off efy_button_text_off"
|
||||
/>
|
||||
<input
|
||||
id="fileSelector"
|
||||
ref="fileSelector"
|
||||
type="file"
|
||||
class="display-none"
|
||||
@change="importPlaylists"
|
||||
<button
|
||||
v-t="'actions.edit_playlist'"
|
||||
class="pp-color h-auto"
|
||||
@click="showPlaylistEditModal(playlist)"
|
||||
/>
|
||||
<button
|
||||
v-t="'actions.delete_playlist'"
|
||||
class="pp-color h-auto"
|
||||
@click="playlistToDelete = playlist.id"
|
||||
/>
|
||||
<label for="fileSelector" v-t="'actions.import_from_json'" class="btn ml-2" role="button" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="video-grid">
|
||||
<div v-for="playlist in playlists" :key="playlist.id" class="efy_trans_filter">
|
||||
<router-link :to="`/playlist?list=${playlist.id}`">
|
||||
<img class="w-full" :src="playlist.thumbnail" alt="thumbnail" />
|
||||
<p
|
||||
style="display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical"
|
||||
class="flex link"
|
||||
:title="playlist.name"
|
||||
v-text="playlist.name"
|
||||
<ModalComponent v-if="playlist.id == playlistToEdit" @close="playlistToEdit = null">
|
||||
<div class="flex flex-col gap-2">
|
||||
<h2 v-t="'actions.edit_playlist'" />
|
||||
<input
|
||||
v-model="newPlaylistName"
|
||||
class="input"
|
||||
type="text"
|
||||
:placeholder="$t('actions.playlist_name')"
|
||||
/>
|
||||
</router-link>
|
||||
<div class="pp-video-card-buttons flex gap-15rem children:m-0" style="flex-wrap: wrap">
|
||||
<button
|
||||
class="thumbnail-overlay thumbnail-right"
|
||||
v-text="`${playlist.videos} ${$t('video.videos')}`"
|
||||
/>
|
||||
<button
|
||||
class="pp-color h-auto"
|
||||
@click="renamePlaylist(playlist.id)"
|
||||
v-t="'actions.rename_playlist'"
|
||||
/>
|
||||
<button
|
||||
class="pp-color h-auto"
|
||||
@click="deletePlaylist(playlist.id)"
|
||||
v-t="'actions.delete_playlist'"
|
||||
<input
|
||||
v-model="newPlaylistDescription"
|
||||
class="input"
|
||||
type="text"
|
||||
:placeholder="$t('actions.playlist_description')"
|
||||
/>
|
||||
<button v-t="'actions.okay'" class="btn ml-auto" @click="editPlaylist(playlist)" />
|
||||
</div>
|
||||
</ModalComponent>
|
||||
<ConfirmModal
|
||||
v-if="playlistToDelete == playlist.id"
|
||||
:message="$t('actions.delete_playlist_confirm')"
|
||||
@close="playlistToDelete = null"
|
||||
@confirm="onDeletePlaylist(playlist.id)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<h5 v-if="bookmarks" v-t="'titles.bookmarks'" class="mb-[15rem]" />
|
||||
<div v-if="bookmarks" class="video-grid">
|
||||
<div
|
||||
v-for="(playlist, index) in bookmarks"
|
||||
:key="playlist.playlistId"
|
||||
class="pp-bookmark video-card efy_trans_filter efy_shadow_trans"
|
||||
>
|
||||
<router-link :to="`/playlist?list=${playlist.playlistId}`">
|
||||
<img class="thumbnail" :src="playlist.thumbnail" alt="thumbnail" />
|
||||
<div class="flex items-center h-[44rem] overflow-hidden">
|
||||
<p class="pp-video-card-title" :title="playlist.name" v-text="playlist.name" />
|
||||
</div>
|
||||
</router-link>
|
||||
<div class="pp-video-card-buttons flex gap-15rem">
|
||||
<button @click.prevent="removeBookmark(index)" class="btn pp-color aspect-square">
|
||||
<font-awesome-icon icon="bookmark" />
|
||||
</button>
|
||||
<button
|
||||
v-text="`${playlist.videos} ${$t('video.videos')}`"
|
||||
class="efy_shadow_trans efy_shadow_button_off efy_button_text_off"
|
||||
/>
|
||||
</div>
|
||||
<a :href="playlist.uploaderUrl" class="pp-video-card-channel">
|
||||
<img class="w-36rem h-36rem efy_shadow_trans" :src="playlist.uploaderAvatar" width="36" height="36" />
|
||||
<div class="pp-text efy_shadow_trans">
|
||||
<span v-text="playlist.uploader" />
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ConfirmModal from "./ConfirmModal.vue";
|
||||
import ModalComponent from "./ModalComponent.vue";
|
||||
|
||||
export default {
|
||||
components: { ConfirmModal, ModalComponent },
|
||||
data() {
|
||||
return {
|
||||
playlists: [],
|
||||
bookmarks: [],
|
||||
playlistToDelete: null,
|
||||
playlistToEdit: null,
|
||||
newPlaylistName: "",
|
||||
newPlaylistDescription: "",
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (this.authenticated) this.fetchPlaylists();
|
||||
else this.$router.push("/login");
|
||||
this.fetchPlaylists();
|
||||
this.loadPlaylistBookmarks();
|
||||
},
|
||||
activated() {
|
||||
document.title = this.$t("titles.playlists") + " - Piped";
|
||||
},
|
||||
methods: {
|
||||
fetchPlaylists() {
|
||||
this.fetchJson(this.authApiUrl() + "/user/playlists", null, {
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
},
|
||||
}).then(json => {
|
||||
this.getPlaylists().then(json => {
|
||||
this.playlists = json;
|
||||
});
|
||||
},
|
||||
renamePlaylist(id) {
|
||||
const newName = prompt(this.$t("actions.new_playlist_name"));
|
||||
if (!newName) return;
|
||||
this.fetchJson(this.authApiUrl() + "/user/playlists/rename", null, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
playlistId: id,
|
||||
newName: newName,
|
||||
}),
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}).then(json => {
|
||||
if (json.error) alert(json.error);
|
||||
else {
|
||||
this.playlists.forEach((playlist, index) => {
|
||||
if (playlist.id == id) {
|
||||
this.playlists[index].name = newName;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
showPlaylistEditModal(playlist) {
|
||||
this.newPlaylistName = playlist.name;
|
||||
this.newPlaylistDescription = playlist.description;
|
||||
this.playlistToEdit = playlist.id;
|
||||
},
|
||||
deletePlaylist(id) {
|
||||
if (confirm(this.$t("actions.delete_playlist_confirm")))
|
||||
this.fetchJson(this.authApiUrl() + "/user/playlists/delete", null, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
playlistId: id,
|
||||
}),
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}).then(json => {
|
||||
editPlaylist(selectedPlaylist) {
|
||||
// save the new name and description since they could be overwritten during the http request
|
||||
const newName = this.newPlaylistName;
|
||||
const newDescription = this.newPlaylistDescription;
|
||||
if (newName != selectedPlaylist.name) {
|
||||
this.renamePlaylist(selectedPlaylist.id, newName).then(json => {
|
||||
if (json.error) alert(json.error);
|
||||
else this.playlists = this.playlists.filter(playlist => playlist.id !== id);
|
||||
else selectedPlaylist.name = newName;
|
||||
});
|
||||
}
|
||||
if (newDescription != selectedPlaylist.description) {
|
||||
this.changePlaylistDescription(selectedPlaylist.id, newDescription).then(json => {
|
||||
if (json.error) alert(json.error);
|
||||
else selectedPlaylist.description = newDescription;
|
||||
});
|
||||
}
|
||||
this.playlistToEdit = null;
|
||||
},
|
||||
onDeletePlaylist(id) {
|
||||
this.deletePlaylist(id).then(json => {
|
||||
if (json.error) alert(json.error);
|
||||
else this.playlists = this.playlists.filter(playlist => playlist.id !== id);
|
||||
});
|
||||
this.playlistToDelete = null;
|
||||
},
|
||||
onCreatePlaylist() {
|
||||
const name = prompt(this.$t("actions.create_playlist"));
|
||||
@ -129,19 +180,6 @@ export default {
|
||||
else this.fetchPlaylists();
|
||||
});
|
||||
},
|
||||
async createPlaylist(name) {
|
||||
let json = await this.fetchJson(this.authApiUrl() + "/user/playlists/create", null, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
name: name,
|
||||
}),
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
return json;
|
||||
},
|
||||
async exportPlaylists() {
|
||||
if (!this.playlists) return;
|
||||
let json = {
|
||||
@ -154,8 +192,8 @@ export default {
|
||||
this.download(JSON.stringify(json), "playlists.json", "application/json");
|
||||
},
|
||||
async fetchPlaylistJson(playlistId) {
|
||||
let playlist = await this.fetchJson(this.authApiUrl() + "/playlists/" + playlistId);
|
||||
let playlistJson = {
|
||||
let playlist = await this.getPlaylist(playlistId);
|
||||
return {
|
||||
name: playlist.name,
|
||||
// possible other types: history, watch later, ...
|
||||
type: "playlist",
|
||||
@ -164,57 +202,69 @@ export default {
|
||||
// list of the videos, starting with "https://youtube.com" to clarify that those are YT videos
|
||||
videos: playlist.relatedStreams.map(stream => "https://youtube.com" + stream.url),
|
||||
};
|
||||
return playlistJson;
|
||||
},
|
||||
async importPlaylists() {
|
||||
const file = this.$refs.fileSelector.files[0];
|
||||
const files = this.$refs.fileSelector.files;
|
||||
for (let file of files) {
|
||||
await this.importPlaylistFile(file);
|
||||
}
|
||||
window.location.reload();
|
||||
},
|
||||
async importPlaylistFile(file) {
|
||||
let text = await file.text();
|
||||
let tasks = [];
|
||||
// list of playlists exported from Piped
|
||||
if (text.includes("playlists")) {
|
||||
if (file.name.slice(-4).toLowerCase() == ".csv") {
|
||||
const lines = text.split("\n");
|
||||
const playlistName = lines[1].split(",")[4];
|
||||
const playlist = {
|
||||
name: playlistName != "" ? playlistName : new Date().toJSON(),
|
||||
videos: lines
|
||||
.slice(4, lines.length)
|
||||
.filter(line => line != "")
|
||||
.slice(1)
|
||||
.map(line => `https://youtube.com/watch?v=${line.split(",")[0]}`),
|
||||
};
|
||||
tasks.push(this.createPlaylistWithVideos(playlist));
|
||||
} else if (text.includes('"Piped"')) {
|
||||
// CSV from Google Takeout
|
||||
let playlists = JSON.parse(text).playlists;
|
||||
if (!playlists.length) {
|
||||
alert(this.$t("actions.no_valid_playlists"));
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < playlists.length; i++) {
|
||||
tasks.push(this.createPlaylistWithVideos(playlists[i]));
|
||||
for (let playlist of playlists) {
|
||||
tasks.push(this.createPlaylistWithVideos(playlist));
|
||||
}
|
||||
// CSV from Google Takeout
|
||||
} else if (file.name.slice(-4).toLowerCase() == ".csv") {
|
||||
const lines = text.split("\n");
|
||||
const playlist = {
|
||||
name: lines[1].split(",")[4],
|
||||
videos: lines
|
||||
.slice(4, lines.length)
|
||||
.filter(line => line != "")
|
||||
.map(line => `https://youtube.com/watch?v=${line.split(",")[0]}`),
|
||||
};
|
||||
tasks.push(this.createPlaylistWithVideos(playlist));
|
||||
} else {
|
||||
alert(this.$t("actions.no_valid_playlists"));
|
||||
return;
|
||||
}
|
||||
await Promise.all(tasks);
|
||||
window.location.reload();
|
||||
},
|
||||
async createPlaylistWithVideos(playlist) {
|
||||
let newPlaylist = await this.createPlaylist(playlist.name);
|
||||
let videoIds = playlist.videos.map(url => url.substr(-11));
|
||||
await this.addVideosToPlaylist(newPlaylist.playlistId, videoIds);
|
||||
},
|
||||
async addVideosToPlaylist(playlistId, videoIds) {
|
||||
await this.fetchJson(this.authApiUrl() + "/user/playlists/add", null, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
playlistId: playlistId,
|
||||
videoIds: videoIds,
|
||||
}),
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
async loadPlaylistBookmarks() {
|
||||
if (!window.db) return;
|
||||
var tx = window.db.transaction("playlist_bookmarks", "readonly");
|
||||
var store = tx.objectStore("playlist_bookmarks");
|
||||
const cursorRequest = store.openCursor();
|
||||
cursorRequest.onsuccess = e => {
|
||||
const cursor = e.target.result;
|
||||
if (cursor) {
|
||||
this.bookmarks.push(cursor.value);
|
||||
cursor.continue();
|
||||
}
|
||||
};
|
||||
},
|
||||
async removeBookmark(index) {
|
||||
var tx = window.db.transaction("playlist_bookmarks", "readwrite");
|
||||
var store = tx.objectStore("playlist_bookmarks");
|
||||
store.delete(this.bookmarks[index].playlistId);
|
||||
this.bookmarks.splice(index, 1);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="pp-pref-cards">
|
||||
<div efy_card="grid">
|
||||
<h2>Quick</h2>
|
||||
<h5>Quick</h5>
|
||||
<label class="pref" for="ddlLanguageSelection">
|
||||
<strong v-t="'actions.language_selection'" />
|
||||
<select
|
||||
@ -85,42 +85,60 @@
|
||||
</select>
|
||||
</label>
|
||||
</template>
|
||||
<br />
|
||||
|
||||
<p v-t="'info.preferences_note'" />
|
||||
<button class="btn" v-t="'actions.reset_preferences'" @click="resetPreferences()" />
|
||||
<button class="btn mx-4" v-t="'actions.backup_preferences'" @click="backupPreferences()" />
|
||||
<label
|
||||
for="fileSelector"
|
||||
class="btn text-center"
|
||||
v-t="'actions.restore_preferences'"
|
||||
@click="restorePreferences()"
|
||||
/>
|
||||
<input class="hidden" id="fileSelector" ref="fileSelector" type="file" @change="restorePreferences()" />
|
||||
|
||||
<div class="pref items-start! flex-col">
|
||||
<strong>Preferences</strong>
|
||||
<div class="flex flex-wrap" style="gap: var(--efy_gap0)">
|
||||
<button style="height: var(--efy_ratio_width)" @click="showConfirmResetPrefsDialog = true">
|
||||
Reset
|
||||
</button>
|
||||
<button style="height: var(--efy_ratio_width)" @click="backupPreferences()">Backup</button>
|
||||
<label for="fileSelector" class="btn text-center" role="button" @click="restorePreferences()">
|
||||
Restore
|
||||
</label>
|
||||
<input
|
||||
id="fileSelector"
|
||||
ref="fileSelector"
|
||||
class="hidden"
|
||||
type="file"
|
||||
@change="restorePreferences()"
|
||||
/>
|
||||
</div>
|
||||
<p v-t="'info.preferences_note'" />
|
||||
<ConfirmModal
|
||||
v-if="showConfirmResetPrefsDialog"
|
||||
:message="$t('actions.confirm_reset_preferences')"
|
||||
@close="showConfirmResetPrefsDialog = false"
|
||||
@confirm="resetPreferences()"
|
||||
/>
|
||||
</div>
|
||||
<!-- options that are visible only when logged in -->
|
||||
<div v-if="this.authenticated">
|
||||
<label class="pp-delete-account pref" for="txtDeleteAccountPassword" efy_card="grid">
|
||||
<h6 v-t="'actions.delete_account'" />
|
||||
<div v-if="authenticated" class="pref items-start! flex-col">
|
||||
<label v-t="'actions.delete_account'" for="txtDeleteAccountPassword" class="font-bold" />
|
||||
<div class="flex flex-wrap" style="gap: var(--efy_gap0)">
|
||||
<input
|
||||
id="txtDeleteAccountPassword"
|
||||
ref="txtDeleteAccountPassword"
|
||||
v-model="password"
|
||||
v-on:keyup.enter="deleteAccount"
|
||||
:placeholder="$t('login.password')"
|
||||
:aria-label="$t('login.password')"
|
||||
class="input w-auto mr-2"
|
||||
class="input mr-2 w-auto"
|
||||
type="password"
|
||||
@keyup.enter="deleteAccount"
|
||||
/>
|
||||
<a class="btn w-full" @click="deleteAccount" v-t="'actions.delete_account'" />
|
||||
</label>
|
||||
<button class="btn w-full" @click="logout" v-t="'actions.logout'" />
|
||||
<button class="btn w-full" @click="invalidateSession" v-t="'actions.invalidate_session'" />
|
||||
<button v-t="'actions.delete_account'" class="w-auto" @click="deleteAccount" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="authenticated" class="pref items-start! flex-col" style="border-bottom: var(--efy_border)">
|
||||
<strong>Logout</strong>
|
||||
<div class="flex flex-wrap" style="gap: var(--efy_gap0)">
|
||||
<button v-t="'actions.logout'" class="w-auto" @click="logout" />
|
||||
<button v-t="'actions.invalidate_session'" class="w-auto" @click="invalidateSession" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div efy_card="grid">
|
||||
<h2 v-t="'titles.player'" />
|
||||
<h5 v-t="'titles.player'" />
|
||||
<label class="pref" for="chkAutoPlayVideo">
|
||||
<strong v-t="'actions.autoplay_video'" />
|
||||
<input
|
||||
@ -131,6 +149,26 @@
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkAutoDisplayCaptions">
|
||||
<strong v-t="'actions.auto_display_captions'" />
|
||||
<input
|
||||
id="chkAutoDisplayCaptions"
|
||||
v-model="autoDisplayCaptions"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkAutoPlayNextCountdown">
|
||||
<strong v-t="'actions.autoplay_next_countdown'" />
|
||||
<input
|
||||
id="chkAutoPlayNextCountdown"
|
||||
v-model="autoPlayNextCountdown"
|
||||
class="input w-24"
|
||||
type="number"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkAudioOnly">
|
||||
<strong v-t="'actions.audio_only'" />
|
||||
<input id="chkAudioOnly" v-model="listen" class="checkbox" type="checkbox" @change="onChange($event)" />
|
||||
@ -157,7 +195,7 @@
|
||||
<input
|
||||
id="txtBufferingGoal"
|
||||
v-model="bufferingGoal"
|
||||
class="input w-auto"
|
||||
class="input w-24"
|
||||
type="text"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
@ -202,6 +240,20 @@
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<!-- chapters layout on mobile -->
|
||||
<label class="pref" for="chkMinimizeChapters">
|
||||
<strong v-t="'actions.chapters_layout_mobile'" />
|
||||
|
||||
<select
|
||||
id="ddlDefaultHomepage"
|
||||
v-model="mobileChapterLayout"
|
||||
class="select w-auto"
|
||||
@change="onChange($event)"
|
||||
>
|
||||
<option v-t="'video.chapters_horizontal'" value="Horizontal" />
|
||||
<option v-t="'video.chapters_vertical'" value="Vertical" />
|
||||
</select>
|
||||
</label>
|
||||
<label class="pref" for="chkShowWatchOnYouTube">
|
||||
<strong v-t="'actions.show_watch_on_youtube'" />
|
||||
<input
|
||||
@ -212,6 +264,16 @@
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkShowSearchSuggestions">
|
||||
<strong v-t="'actions.show_search_suggestions'" />
|
||||
<input
|
||||
id="chkShowSearchSuggestions"
|
||||
v-model="searchSuggestions"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkStoreSearchHistory">
|
||||
<strong v-t="'actions.store_search_history'" />
|
||||
<input
|
||||
@ -247,7 +309,7 @@
|
||||
<select
|
||||
id="ddlEnabledCodecs"
|
||||
v-model="enabledCodecs"
|
||||
class="select w-auto h-auto"
|
||||
class="select h-auto w-auto"
|
||||
multiple
|
||||
@change="onChange($event)"
|
||||
>
|
||||
@ -279,12 +341,16 @@
|
||||
</div>
|
||||
|
||||
<div efy_card="grid">
|
||||
<h2>SponsorBlock</h2>
|
||||
<p>
|
||||
<h5>SponsorBlock + DeArrow</h5>
|
||||
<p class="pref" style="justify-content: unset !important">
|
||||
<span v-t="'actions.uses_api_from'" /><a class="link" href="https://sponsor.ajay.app/"
|
||||
>sponsor.ajay.app</a
|
||||
>
|
||||
</p>
|
||||
<label class="pref" for="chkDeArrow">
|
||||
<strong v-t="'actions.enable_dearrow'" />
|
||||
<input id="chkDeArrow" v-model="dearrow" class="checkbox" type="checkbox" @change="onChange($event)" />
|
||||
</label>
|
||||
<label class="pref" for="chkEnableSponsorblock">
|
||||
<strong v-t="'actions.enable_sponsorblock'" />
|
||||
<input
|
||||
@ -295,106 +361,41 @@
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkSkipSponsors">
|
||||
<strong v-t="'actions.skip_sponsors'" />
|
||||
<input
|
||||
id="chkSkipSponsors"
|
||||
v-model="skipSponsor"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkSkipIntro">
|
||||
<strong v-t="'actions.skip_intro'" />
|
||||
<input
|
||||
id="chkSkipIntro"
|
||||
v-model="skipIntro"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkSkipOutro">
|
||||
<strong v-t="'actions.skip_outro'" />
|
||||
<input
|
||||
id="chkSkipOutro"
|
||||
v-model="skipOutro"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkSkipPreview">
|
||||
<strong v-t="'actions.skip_preview'" />
|
||||
<input
|
||||
id="chkSkipPreview"
|
||||
v-model="skipPreview"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkSkipInteraction">
|
||||
<strong v-t="'actions.skip_interaction'" />
|
||||
<input
|
||||
id="chkSkipInteraction"
|
||||
v-model="skipInteraction"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkSkipSelfPromo">
|
||||
<strong v-t="'actions.skip_self_promo'" />
|
||||
<input
|
||||
id="chkSkipSelfPromo"
|
||||
v-model="skipSelfPromo"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkSkipNonMusic">
|
||||
<strong v-t="'actions.skip_non_music'" />
|
||||
<input
|
||||
id="chkSkipNonMusic"
|
||||
v-model="skipMusicOffTopic"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkSkipHighlight">
|
||||
<strong v-t="'actions.skip_highlight'" />
|
||||
<input
|
||||
id="chkSkipHighlight"
|
||||
v-model="skipHighlight"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkSkipFiller">
|
||||
<strong v-t="'actions.skip_filler_tangent'" />
|
||||
<input
|
||||
id="chkSkipFiller"
|
||||
v-model="skipFiller"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="chkShowMarkers">
|
||||
<strong v-t="'actions.show_markers'" />
|
||||
<input
|
||||
id="chkShowMarkers"
|
||||
v-model="showMarkers"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<div v-if="sponsorBlock">
|
||||
<label v-for="[name, item] in skipOptions" :key="name" class="pref" :for="'ddlSkip_' + name">
|
||||
<strong v-t="item.label" />
|
||||
<select
|
||||
:id="'ddlSkip_' + name"
|
||||
v-model="item.value"
|
||||
class="select w-auto"
|
||||
@change="onChange($event)"
|
||||
>
|
||||
<option v-t="'actions.no'" value="no" />
|
||||
<option v-t="'actions.skip_button_only'" value="button" />
|
||||
<option v-t="'actions.skip_automatically'" value="auto" />
|
||||
</select>
|
||||
</label>
|
||||
<label class="pref" for="chkShowMarkers">
|
||||
<strong v-t="'actions.show_markers'" />
|
||||
<input
|
||||
id="chkShowMarkers"
|
||||
v-model="showMarkers"
|
||||
class="checkbox"
|
||||
type="checkbox"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
<label class="pref" for="txtMinSegmentLength" style="border-bottom: var(--efy_border)">
|
||||
<strong v-t="'actions.min_segment_length'" />
|
||||
<input
|
||||
id="txtMinSegmentLength"
|
||||
v-model="minSegmentLength"
|
||||
class="input w-24"
|
||||
type="text"
|
||||
@change="onChange($event)"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -406,7 +407,7 @@
|
||||
<th v-t="'preferences.instance_locations'" />
|
||||
<th v-t="'preferences.has_cdn'" />
|
||||
<th v-t="'preferences.registered_users'" />
|
||||
<th class="lt-md:hidden" v-t="'preferences.version'" />
|
||||
<th v-t="'preferences.version'" class="lt-md:hidden" />
|
||||
<th v-t="'preferences.up_to_date'" />
|
||||
<th v-t="'preferences.ssl_score'" />
|
||||
</tr>
|
||||
@ -420,7 +421,7 @@
|
||||
<td class="lt-md:hidden" v-text="instance.version" />
|
||||
<td v-text="`${instance.up_to_date ? '✅' : '❌'}`" />
|
||||
<td>
|
||||
<a :href="sslScore(instance.api_url)" target="_blank" v-t="'actions.view_ssl_score'" />
|
||||
<a v-t="'actions.view_ssl_score'" :href="sslScore(instance.api_url)" target="_blank" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -429,26 +430,37 @@
|
||||
|
||||
<script>
|
||||
import CountryMap from "@/utils/CountryMaps/en.json";
|
||||
import ConfirmModal from "./ConfirmModal.vue";
|
||||
export default {
|
||||
components: {
|
||||
ConfirmModal,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mobileChapterLayout: "Vertical",
|
||||
selectedInstance: null,
|
||||
authInstance: false,
|
||||
selectedAuthInstance: null,
|
||||
instances: [],
|
||||
sponsorBlock: true,
|
||||
skipSponsor: true,
|
||||
skipIntro: false,
|
||||
skipOutro: false,
|
||||
skipPreview: false,
|
||||
skipInteraction: true,
|
||||
skipSelfPromo: true,
|
||||
skipMusicOffTopic: true,
|
||||
skipHighlight: false,
|
||||
skipFiller: false,
|
||||
skipOptions: new Map([
|
||||
["sponsor", { value: "auto", label: "actions.skip_sponsors" }],
|
||||
["intro", { value: "no", label: "actions.skip_intro" }],
|
||||
["outro", { value: "no", label: "actions.skip_outro" }],
|
||||
["preview", { value: "no", label: "actions.skip_preview" }],
|
||||
["interaction", { value: "auto", label: "actions.skip_interaction" }],
|
||||
["selfpromo", { value: "auto", label: "actions.skip_self_promo" }],
|
||||
["music_offtopic", { value: "auto", label: "actions.skip_non_music" }],
|
||||
["poi_highlight", { value: "no", label: "actions.skip_highlight" }],
|
||||
["filler", { value: "no", label: "actions.skip_filler_tangent" }],
|
||||
]),
|
||||
showMarkers: true,
|
||||
minSegmentLength: 0,
|
||||
dearrow: false,
|
||||
selectedTheme: "dark",
|
||||
autoPlayVideo: true,
|
||||
autoDisplayCaptions: false,
|
||||
autoPlayNextCountdown: 5,
|
||||
listen: false,
|
||||
resolutions: [144, 240, 360, 480, 720, 1080, 1440, 2160, 4320],
|
||||
defaultQuality: 0,
|
||||
@ -461,6 +473,7 @@ export default {
|
||||
minimizeRecommendations: false,
|
||||
minimizeChapters: false,
|
||||
showWatchOnYouTube: false,
|
||||
searchSuggestions: true,
|
||||
watchHistory: false,
|
||||
searchHistory: false,
|
||||
hideWatched: false,
|
||||
@ -468,6 +481,7 @@ export default {
|
||||
languages: [
|
||||
{ code: "ar", name: "Arabic" },
|
||||
{ code: "az", name: "Azərbaycan" },
|
||||
{ code: "bg", name: "Български" },
|
||||
{ code: "bn", name: "বাংলা" },
|
||||
{ code: "bs", name: "Bosanski" },
|
||||
{ code: "ca", name: "Català" },
|
||||
@ -495,6 +509,7 @@ export default {
|
||||
{ code: "ml", name: "മലയാളം" },
|
||||
{ code: "nb_NO", name: "Norwegian Bokmål" },
|
||||
{ code: "nl", name: "Nederlands" },
|
||||
{ code: "oc", name: "Occitan" },
|
||||
{ code: "or", name: "ଓଡ଼ିଆ" },
|
||||
{ code: "pl", name: "Polski" },
|
||||
{ code: "pt", name: "Português" },
|
||||
@ -502,6 +517,7 @@ export default {
|
||||
{ code: "pt_BR", name: "Português (Brasil)" },
|
||||
{ code: "ro", name: "Română" },
|
||||
{ code: "ru", name: "Русский" },
|
||||
{ code: "si", name: "සිංහල" },
|
||||
{ code: "sr", name: "Српски" },
|
||||
{ code: "sv", name: "Svenska" },
|
||||
{ code: "ta", name: "தமிழ்" },
|
||||
@ -516,6 +532,7 @@ export default {
|
||||
disableLBRY: false,
|
||||
proxyLBRY: false,
|
||||
password: null,
|
||||
showConfirmResetPrefsDialog: false,
|
||||
};
|
||||
},
|
||||
activated() {
|
||||
@ -526,7 +543,7 @@ export default {
|
||||
|
||||
this.fetchJson("https://piped-instances.kavin.rocks/").then(resp => {
|
||||
this.instances = resp;
|
||||
if (this.instances.filter(instance => instance.api_url == this.apiUrl()).length == 0)
|
||||
if (!this.instances.some(instance => instance.api_url == this.apiUrl()))
|
||||
this.instances.push({
|
||||
name: "Custom Instance",
|
||||
api_url: this.apiUrl(),
|
||||
@ -541,57 +558,30 @@ export default {
|
||||
this.selectedAuthInstance = this.getPreferenceString("auth_instance_url", this.selectedInstance);
|
||||
|
||||
this.sponsorBlock = this.getPreferenceBoolean("sponsorblock", true);
|
||||
if (localStorage.getItem("selectedSkip") !== null) {
|
||||
var skipList = localStorage.getItem("selectedSkip").split(",");
|
||||
this.skipSponsor =
|
||||
this.skipIntro =
|
||||
this.skipOutro =
|
||||
this.skipPreview =
|
||||
this.skipInteraction =
|
||||
this.skipSelfPromo =
|
||||
this.skipMusicOffTopic =
|
||||
this.skipHighlight =
|
||||
this.skipFiller =
|
||||
false;
|
||||
var skipOptions, skipList;
|
||||
if ((skipOptions = this.getPreferenceJSON("skipOptions")) !== undefined) {
|
||||
Object.entries(skipOptions).forEach(([key, value]) => {
|
||||
var opt = this.skipOptions.get(key);
|
||||
if (opt !== undefined) opt.value = value;
|
||||
else console.log("Unknown sponsor type: " + key);
|
||||
});
|
||||
} else if ((skipList = this.getPreferenceString("selectedSkip")) !== undefined) {
|
||||
skipList = skipList.split(",");
|
||||
this.skipOptions.forEach(opt => (opt.value = "no"));
|
||||
skipList.forEach(skip => {
|
||||
switch (skip) {
|
||||
case "sponsor":
|
||||
this.skipSponsor = true;
|
||||
break;
|
||||
case "intro":
|
||||
this.skipIntro = true;
|
||||
break;
|
||||
case "outro":
|
||||
this.skipOutro = true;
|
||||
break;
|
||||
case "preview":
|
||||
this.skipPreview = true;
|
||||
break;
|
||||
case "interaction":
|
||||
this.skipInteraction = true;
|
||||
break;
|
||||
case "selfpromo":
|
||||
this.skipSelfPromo = true;
|
||||
break;
|
||||
case "music_offtopic":
|
||||
this.skipMusicOffTopic = true;
|
||||
break;
|
||||
case "poi_highlight":
|
||||
this.skipHighlight = true;
|
||||
break;
|
||||
case "filler":
|
||||
this.skipFiller = true;
|
||||
break;
|
||||
default:
|
||||
console.log("Unknown sponsor type: " + skip);
|
||||
break;
|
||||
}
|
||||
var opt = this.skipOptions.get(skip);
|
||||
if (opt !== undefined) opt.value = "auto";
|
||||
else console.log("Unknown sponsor type: " + skip);
|
||||
});
|
||||
}
|
||||
|
||||
this.showMarkers = this.getPreferenceBoolean("showMarkers", true);
|
||||
this.minSegmentLength = Math.max(this.getPreferenceNumber("minSegmentLength", 0), 0);
|
||||
this.dearrow = this.getPreferenceBoolean("dearrow", false);
|
||||
this.selectedTheme = this.getPreferenceString("theme", "dark");
|
||||
this.autoPlayVideo = this.getPreferenceBoolean("playerAutoPlay", true);
|
||||
this.autoDisplayCaptions = this.getPreferenceBoolean("autoDisplayCaptions", false);
|
||||
this.autoPlayNextCountdown = this.getPreferenceNumber("autoPlayNextCountdown", 5);
|
||||
this.listen = this.getPreferenceBoolean("listen", false);
|
||||
this.defaultQuality = Number(localStorage.getItem("quality"));
|
||||
this.bufferingGoal = Math.max(Number(localStorage.getItem("bufferGoal")), 10);
|
||||
@ -602,6 +592,7 @@ export default {
|
||||
this.minimizeRecommendations = this.getPreferenceBoolean("minimizeRecommendations", false);
|
||||
this.minimizeChapters = this.getPreferenceBoolean("minimizeChapters", false);
|
||||
this.showWatchOnYouTube = this.getPreferenceBoolean("showWatchOnYouTube", false);
|
||||
this.searchSuggestions = this.getPreferenceBoolean("searchSuggestions", true);
|
||||
this.watchHistory = this.getPreferenceBoolean("watchHistory", false);
|
||||
this.searchHistory = this.getPreferenceBoolean("searchHistory", false);
|
||||
this.selectedLanguage = this.getPreferenceString("hl", await this.defaultLanguage);
|
||||
@ -609,6 +600,7 @@ export default {
|
||||
this.disableLBRY = this.getPreferenceBoolean("disableLBRY", false);
|
||||
this.proxyLBRY = this.getPreferenceBoolean("proxyLBRY", false);
|
||||
this.hideWatched = this.getPreferenceBoolean("hideWatched", false);
|
||||
this.mobileChapterLayout = this.getPreferenceString("mobileChapterLayout", "Vertical");
|
||||
if (this.selectedLanguage != "en") {
|
||||
try {
|
||||
this.CountryMap = await import(`../utils/CountryMaps/${this.selectedLanguage}.json`).then(
|
||||
@ -638,21 +630,19 @@ export default {
|
||||
localStorage.setItem("auth_instance_url", this.selectedAuthInstance);
|
||||
localStorage.setItem("sponsorblock", this.sponsorBlock);
|
||||
|
||||
var sponsorSelected = [];
|
||||
if (this.skipSponsor) sponsorSelected.push("sponsor");
|
||||
if (this.skipIntro) sponsorSelected.push("intro");
|
||||
if (this.skipOutro) sponsorSelected.push("outro");
|
||||
if (this.skipPreview) sponsorSelected.push("preview");
|
||||
if (this.skipInteraction) sponsorSelected.push("interaction");
|
||||
if (this.skipSelfPromo) sponsorSelected.push("selfpromo");
|
||||
if (this.skipMusicOffTopic) sponsorSelected.push("music_offtopic");
|
||||
if (this.skipHighlight) sponsorSelected.push("poi_highlight");
|
||||
if (this.skipFiller) sponsorSelected.push("filler");
|
||||
localStorage.setItem("selectedSkip", sponsorSelected);
|
||||
var skipOptions = {};
|
||||
this.skipOptions.forEach((v, k) => (skipOptions[k] = v.value));
|
||||
localStorage.setItem("skipOptions", JSON.stringify(skipOptions));
|
||||
|
||||
localStorage.setItem("showMarkers", this.showMarkers);
|
||||
localStorage.setItem("minSegmentLength", this.minSegmentLength);
|
||||
|
||||
localStorage.setItem("dearrow", this.dearrow);
|
||||
|
||||
localStorage.setItem("theme", this.selectedTheme);
|
||||
localStorage.setItem("playerAutoPlay", this.autoPlayVideo);
|
||||
localStorage.setItem("autoDisplayCaptions", this.autoDisplayCaptions);
|
||||
localStorage.setItem("autoPlayNextCountdown", this.autoPlayNextCountdown);
|
||||
localStorage.setItem("listen", this.listen);
|
||||
localStorage.setItem("quality", this.defaultQuality);
|
||||
localStorage.setItem("bufferGoal", this.bufferingGoal);
|
||||
@ -663,6 +653,7 @@ export default {
|
||||
localStorage.setItem("minimizeRecommendations", this.minimizeRecommendations);
|
||||
localStorage.setItem("minimizeChapters", this.minimizeChapters);
|
||||
localStorage.setItem("showWatchOnYouTube", this.showWatchOnYouTube);
|
||||
localStorage.setItem("searchSuggestions", this.searchSuggestions);
|
||||
localStorage.setItem("watchHistory", this.watchHistory);
|
||||
localStorage.setItem("searchHistory", this.searchHistory);
|
||||
if (!this.searchHistory) localStorage.removeItem("search_history");
|
||||
@ -671,6 +662,7 @@ export default {
|
||||
localStorage.setItem("disableLBRY", this.disableLBRY);
|
||||
localStorage.setItem("proxyLBRY", this.proxyLBRY);
|
||||
localStorage.setItem("hideWatched", this.hideWatched);
|
||||
localStorage.setItem("mobileChapterLayout", this.mobileChapterLayout);
|
||||
|
||||
if (shouldReload) window.location.reload();
|
||||
}
|
||||
@ -700,7 +692,7 @@ export default {
|
||||
window.location = "/";
|
||||
},
|
||||
resetPreferences() {
|
||||
if (!confirm(this.$t("actions.confirm_reset_preferences"))) return;
|
||||
this.showConfirmResetPrefsDialog = false;
|
||||
// clear the local storage
|
||||
localStorage.clear();
|
||||
// redirect to the home page
|
||||
@ -739,5 +731,37 @@ export default {
|
||||
<style>
|
||||
.pref {
|
||||
@apply flex justify-between items-center;
|
||||
padding: 10rem;
|
||||
border-top: var(--efy_border);
|
||||
gap: 10rem;
|
||||
}
|
||||
/*.pref:nth-child(odd) {
|
||||
background: var(--efy_bg1);
|
||||
}*/
|
||||
.pref :is(input, select, button, [role="button"]) {
|
||||
margin: 0;
|
||||
}
|
||||
.pref strong {
|
||||
line-height: 1;
|
||||
}
|
||||
.pref :is([type="number"], [type="text"], select) {
|
||||
min-width: 60rem;
|
||||
max-width: 250rem;
|
||||
}
|
||||
.pp-pref-cards {
|
||||
margin-top: 15rem;
|
||||
}
|
||||
[efy_card*="grid"] {
|
||||
padding: 0;
|
||||
gap: 0;
|
||||
}
|
||||
[efy_card*="grid"]:active {
|
||||
transform: scale(1) !important;
|
||||
}
|
||||
[efy_card*="grid"] h5 {
|
||||
padding: 5rem 10rem;
|
||||
}
|
||||
tbody:nth-child(odd) {
|
||||
background: var(--efy_bg1) !important;
|
||||
}
|
||||
</style>
|
||||
|
30
src/components/QrCode.vue
Normal file
30
src/components/QrCode.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<canvas ref="qrCodeCanvas" style="border-radius: var(--efy_radius)" />
|
||||
</template>
|
||||
<script>
|
||||
import QRCode from "qrcode";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
text: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
text() {
|
||||
this.generateQrCode();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.generateQrCode();
|
||||
},
|
||||
methods: {
|
||||
generateQrCode() {
|
||||
QRCode.toCanvas(this.$refs.qrCodeCanvas, this.text, error => {
|
||||
if (error) console.error(error);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
114
src/components/RegisterPage.vue
Normal file
114
src/components/RegisterPage.vue
Normal file
@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<h1 v-t="'titles.register'" class="my-4 text-center font-bold" />
|
||||
<hr />
|
||||
<div class="flex justify-center text-center">
|
||||
<form class="items-center px-3 children:pb-3">
|
||||
<div>
|
||||
<input
|
||||
v-model="username"
|
||||
class="input w-full"
|
||||
type="text"
|
||||
autocomplete="username"
|
||||
:placeholder="$t('login.username')"
|
||||
:aria-label="$t('login.username')"
|
||||
@keyup.enter="register"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
<input
|
||||
v-model="password"
|
||||
class="input w-full"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
autocomplete="password"
|
||||
:placeholder="$t('login.password')"
|
||||
:aria-label="$t('login.password')"
|
||||
@keyup.enter="register"
|
||||
/>
|
||||
<button type="button" class="btn ml-2" @click="showPassword = !showPassword">
|
||||
<div class="i-fa6-solid:eye" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
<input
|
||||
v-model="passwordConfirm"
|
||||
class="input w-full"
|
||||
:type="showConfirmPassword ? 'text' : 'password'"
|
||||
autocomplete="password"
|
||||
:placeholder="$t('login.password_confirm')"
|
||||
:aria-label="$t('login.password_confirm')"
|
||||
@keyup.enter="register"
|
||||
/>
|
||||
<button type="button" class="btn ml-2" @click="showConfirmPassword = !showConfirmPassword">
|
||||
<div class="i-fa6-solid:eye" />
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<a v-t="'titles.register'" class="btn w-auto" @click="register" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<ConfirmModal
|
||||
v-if="showUnsecureRegisterDialog"
|
||||
:message="$t('info.register_no_email_note')"
|
||||
@close="showUnsecureRegisterDialog = false"
|
||||
@confirm="
|
||||
forceUnsecureRegister = true;
|
||||
showUnsecureRegisterDialog = false;
|
||||
register();
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isEmail } from "../utils/Misc.js";
|
||||
import ConfirmModal from "./ConfirmModal.vue";
|
||||
|
||||
export default {
|
||||
components: { ConfirmModal },
|
||||
data() {
|
||||
return {
|
||||
username: null,
|
||||
password: null,
|
||||
passwordConfirm: null,
|
||||
showPassword: false,
|
||||
showConfirmPassword: false,
|
||||
showUnsecureRegisterDialog: false,
|
||||
forceUnsecureRegister: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
//TODO: Add Server Side check
|
||||
if (this.getAuthToken()) {
|
||||
this.$router.push("/");
|
||||
}
|
||||
},
|
||||
activated() {
|
||||
document.title = "Register - Piped";
|
||||
},
|
||||
methods: {
|
||||
register() {
|
||||
if (!this.username || !this.password) return;
|
||||
if (this.password != this.passwordConfirm) {
|
||||
alert(this.$t("login.passwords_incorrect"));
|
||||
return;
|
||||
}
|
||||
if (isEmail(this.username) && !this.forceUnsecureRegister) {
|
||||
this.showUnsecureRegisterDialog = true;
|
||||
return;
|
||||
}
|
||||
this.fetchJson(this.authApiUrl() + "/register", null, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
username: this.username,
|
||||
password: this.password,
|
||||
}),
|
||||
}).then(resp => {
|
||||
if (resp.token) {
|
||||
this.setPreference("authToken" + this.hashCode(this.authApiUrl()), resp.token);
|
||||
window.location = "/"; // done to bypass cache
|
||||
} else alert(resp.error);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
@ -1,13 +1,20 @@
|
||||
<template>
|
||||
<h1 class="text-center my-2" v-text="$route.query.search_query" />
|
||||
|
||||
<label for="ddlSearchFilters" class="mr-2">
|
||||
<strong v-text="`${$t('actions.filter')}:`" />
|
||||
</label>
|
||||
<select id="ddlSearchFilters" v-model="selectedFilter" default="all" class="select w-auto" @change="updateFilter()">
|
||||
<option v-for="filter in availableFilters" :key="filter" :value="filter" v-t="`search.${filter}`" />
|
||||
</select>
|
||||
|
||||
<hr />
|
||||
<div class="flex flex-wrap place-content-between items-center">
|
||||
<h5 class="ml-[5rem]" v-text="$route.query.search_query" />
|
||||
<div class="flex items-center" style="gap: var(--efy_gap0)">
|
||||
<label v-text="`${$t('actions.filter')}:`" for="ddlSearchFilters" />
|
||||
<select
|
||||
id="ddlSearchFilters"
|
||||
v-model="selectedFilter"
|
||||
default="all"
|
||||
class="w-auto; m-0"
|
||||
@change="updateFilter()"
|
||||
>
|
||||
<option v-for="filter in availableFilters" :key="filter" v-t="`search.${filter}`" :value="filter" />
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
<div v-if="results && results.corrected">
|
||||
@ -18,19 +25,21 @@
|
||||
</i18n-t>
|
||||
</div>
|
||||
|
||||
<div v-if="results" class="video-grid">
|
||||
<LoadingIndicatorPage :show-content="results != null && results.items?.length" class="video-grid">
|
||||
<template v-for="result in results.items" :key="result.url">
|
||||
<ContentItem :item="result" height="94" width="168" />
|
||||
</template>
|
||||
</div>
|
||||
</LoadingIndicatorPage>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ContentItem from "./ContentItem.vue";
|
||||
import LoadingIndicatorPage from "./LoadingIndicatorPage.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ContentItem,
|
||||
LoadingIndicatorPage,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -44,6 +53,7 @@ export default {
|
||||
"music_videos",
|
||||
"music_albums",
|
||||
"music_playlists",
|
||||
"music_artists",
|
||||
],
|
||||
selectedFilter: this.$route.query.filter ?? "all",
|
||||
};
|
||||
@ -72,7 +82,10 @@ export default {
|
||||
},
|
||||
async updateResults() {
|
||||
document.title = this.$route.query.search_query + " - Piped";
|
||||
this.results = this.fetchResults().then(json => (this.results = json));
|
||||
this.results = this.fetchResults().then(json => {
|
||||
this.results = json;
|
||||
this.updateWatched(this.results.items);
|
||||
});
|
||||
},
|
||||
updateFilter() {
|
||||
this.$router.replace({
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="absolute suggestions-container">
|
||||
<div class="suggestions-container absolute">
|
||||
<ul>
|
||||
<li
|
||||
v-for="(suggestion, i) in searchSuggestions"
|
||||
@ -50,12 +50,16 @@ export default {
|
||||
if (!this.searchText) {
|
||||
if (this.getPreferenceBoolean("searchHistory", false))
|
||||
this.searchSuggestions = JSON.parse(localStorage.getItem("search_history")) ?? [];
|
||||
} else if (this.getPreferenceBoolean("searchSuggestions", true)) {
|
||||
this.searchSuggestions =
|
||||
(
|
||||
await this.fetchJson(this.apiUrl() + "/opensearch/suggestions", {
|
||||
query: this.searchText,
|
||||
})
|
||||
)?.[1] ?? [];
|
||||
} else {
|
||||
this.searchSuggestions = (
|
||||
await this.fetchJson(this.apiUrl() + "/opensearch/suggestions", {
|
||||
query: this.searchText,
|
||||
})
|
||||
)?.[1];
|
||||
this.searchSuggestions = [];
|
||||
return;
|
||||
}
|
||||
this.searchSuggestions.unshift(this.searchText);
|
||||
this.setSelected(0);
|
||||
@ -86,6 +90,6 @@ export default {
|
||||
background: var(--efy_text2);
|
||||
box-shadow: 0 0 20rem var(--efy_text_trans);
|
||||
padding: var(--efy_gap);
|
||||
margin: calc(-12rem + var(--efy_gap)) 0 var(--efy_gap) 0;
|
||||
margin: calc(40rem + var(--efy_gap)) 0 var(--efy_gap) 0;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,36 +1,47 @@
|
||||
<template>
|
||||
<ModalComponent>
|
||||
<h4 v-t="'actions.share'" />
|
||||
<h5 v-t="'actions.share'" />
|
||||
<div class="flex justify-between mt-2 mb-2">
|
||||
<label v-t="'actions.piped_link'" />
|
||||
<input type="checkbox" v-model="pipedLink" @change="onChange" />
|
||||
<input v-model="pipedLink" type="checkbox" @change="onChange" />
|
||||
</div>
|
||||
<div v-if="this.hasPlaylist" class="flex justify-between">
|
||||
<div v-if="hasPlaylist" class="flex justify-between">
|
||||
<label v-t="'actions.with_playlist'" />
|
||||
<input type="checkbox" v-model="withPlaylist" @change="onChange" />
|
||||
<input v-model="withPlaylist" type="checkbox" @change="onChange" />
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<label v-t="'actions.with_timecode'" for="withTimeCode" />
|
||||
<input id="withTimeCode" type="checkbox" v-model="withTimeCode" @change="onChange" />
|
||||
<input id="withTimeCode" v-model="withTimeCode" type="checkbox" @change="onChange" />
|
||||
</div>
|
||||
<div v-if="this.withTimeCode" class="flex justify-between mt-2" style="align-items: center">
|
||||
<div v-if="withTimeCode" class="flex justify-between mt-2" style="align-items: center">
|
||||
<label v-t="'actions.time_code'" />
|
||||
<input class="input w-300 mb-0rem" type="text" v-model="timeStamp" />
|
||||
<input v-model="timeStamp" style="max-width: 100rem" type="number" @change="onChange" />
|
||||
</div>
|
||||
<a :href="generatedLink" target="_blank">
|
||||
<h6 class="mb-2 mt-2" v-text="generatedLink" />
|
||||
</a>
|
||||
<div class="flex justify-end mt-4">
|
||||
<button class="btn" style="margin-right: 15rem" v-t="'actions.follow_link'" @click="followLink()" />
|
||||
<button class="btn" v-t="'actions.copy_link'" @click="copyLink()" />
|
||||
<QrCode v-if="showQrCode" :text="generatedLink" class="mb-[10rem]" />
|
||||
<div class="flex flex-wrap justify-end" style="gap: var(--efy_gap0)">
|
||||
<button v-t="'actions.generate_qrcode'" class="btn" @click="showQrCode = !showQrCode" />
|
||||
<button v-t="'actions.follow_link'" class="btn ml-3" @click="followLink()" />
|
||||
<button v-t="'actions.copy_link'" class="btn ml-3" @click="copyLink()" />
|
||||
</div>
|
||||
</ModalComponent>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineAsyncComponent } from "vue";
|
||||
|
||||
const QrCode = defineAsyncComponent(() => import("./QrCode.vue"));
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import ModalComponent from "./ModalComponent.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ModalComponent,
|
||||
},
|
||||
props: {
|
||||
videoId: {
|
||||
type: String,
|
||||
@ -42,14 +53,13 @@ export default {
|
||||
},
|
||||
playlistId: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
playlistIndex: {
|
||||
type: Number,
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
ModalComponent,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
withTimeCode: true,
|
||||
@ -57,8 +67,23 @@ export default {
|
||||
withPlaylist: true,
|
||||
timeStamp: null,
|
||||
hasPlaylist: false,
|
||||
showQrCode: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
generatedLink() {
|
||||
var baseUrl = this.pipedLink
|
||||
? window.location.origin + "/watch?v=" + this.videoId
|
||||
: "https://youtu.be/" + this.videoId;
|
||||
var url = new URL(baseUrl);
|
||||
if (this.withTimeCode && this.timeStamp > 0) url.searchParams.append("t", this.timeStamp);
|
||||
if (this.hasPlaylist && this.withPlaylist) {
|
||||
url.searchParams.append("list", this.playlistId);
|
||||
url.searchParams.append("index", this.playlistIndex);
|
||||
}
|
||||
return url.href;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.timeStamp = parseInt(this.currentTime);
|
||||
this.withTimeCode = this.getPreferenceBoolean("shareWithTimeCode", true);
|
||||
@ -87,19 +112,5 @@ export default {
|
||||
this.setPreference("shareWithPlaylist", this.withPlaylist, true);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
generatedLink() {
|
||||
var baseUrl = this.pipedLink
|
||||
? window.location.origin + "/watch?v=" + this.videoId
|
||||
: "https://youtu.be/" + this.videoId;
|
||||
var url = new URL(baseUrl);
|
||||
if (this.withTimeCode && this.timeStamp > 0) url.searchParams.append("t", this.timeStamp);
|
||||
if (this.hasPlaylist && this.withPlaylist) {
|
||||
url.searchParams.append("list", this.playlistId);
|
||||
url.searchParams.append("index", this.playlistIndex);
|
||||
}
|
||||
return url.href;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<label for="ddlSortBy" v-t="'actions.sort_by'" class="mr-2" />
|
||||
<select id="ddlSortBy" v-model="selectedSort" class="select w-auto m-0">
|
||||
<option v-for="(value, key) in options" v-t="`actions.${key}`" :key="key" :value="value" />
|
||||
<label v-t="'actions.sort_by'" for="ddlSortBy" class="m-0" />
|
||||
<select id="ddlSortBy" v-model="selectedSort" class="w-auto m-0">
|
||||
<option v-for="(value, key) in options" :key="key" v-t="`actions.${key}`" :value="value" />
|
||||
</select>
|
||||
</template>
|
||||
|
||||
@ -18,7 +18,10 @@ const options = {
|
||||
const selectedSort = ref("descending");
|
||||
|
||||
const props = defineProps({
|
||||
byKey: String,
|
||||
byKey: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["apply"]);
|
||||
|
@ -1,29 +1,100 @@
|
||||
<template>
|
||||
<div class="flex justify-between w-full">
|
||||
<div class="flex">
|
||||
<button class="btn mr-2">
|
||||
<router-link to="/import" v-t="'actions.import_from_json'" />
|
||||
</button>
|
||||
<button class="btn" @click="exportHandler" v-t="'actions.export_to_json'" />
|
||||
<hr />
|
||||
<!-- import / export section -->
|
||||
<div class="flex justify-between flex-wrap m0c">
|
||||
<div efy_card class="w-auto!" style="padding: var(--efy_padding)">
|
||||
<i18n-t keypath="titles.subscriptions" efy_card />{{ ": " + subscriptions.length }}
|
||||
</div>
|
||||
<i18n-t keypath="subscriptions.subscribed_channels_count">{{ subscriptions.length }}</i18n-t>
|
||||
<div class="m0c flex flex-wrap">
|
||||
<router-link v-t="'actions.import_from_json_csv'" to="/import" role="button" />
|
||||
<button v-t="'actions.export_to_json'" @click="exportHandler" />
|
||||
<input
|
||||
id="fileSelector"
|
||||
ref="fileSelector"
|
||||
type="file"
|
||||
class="display-none"
|
||||
multiple="multiple"
|
||||
@change="importGroupsHandler"
|
||||
/>
|
||||
<label
|
||||
for="fileSelector"
|
||||
role="button"
|
||||
v-text="`${$t('actions.import_from_json')} (${$t('titles.channel_groups')})`"
|
||||
class="font-bold"
|
||||
/>
|
||||
<button
|
||||
@click="exportGroupsHandler"
|
||||
v-text="`${$t('actions.export_to_json')} (${$t('titles.channel_groups')})`"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="m0c w-full flex flex-wrap">
|
||||
<button
|
||||
v-for="group in channelGroups"
|
||||
:key="group.groupName"
|
||||
class="flex gap-[10rem] items-center"
|
||||
:class="{ selected: selectedGroup === group }"
|
||||
@click="selectGroup(group)"
|
||||
>
|
||||
<span v-text="group.groupName !== '' ? group.groupName : $t('video.all')" />
|
||||
<div v-if="group.groupName != '' && selectedGroup == group" class="flex flex-wrap gap-[10rem] items-center">
|
||||
<div>|</div>
|
||||
<font-awesome-icon class="mx-2" icon="edit" @click="showEditGroupModal = true" />
|
||||
<div>|</div>
|
||||
<font-awesome-icon class="mx-2" icon="circle-minus" @click="deleteGroup(group)" />
|
||||
</div>
|
||||
</button>
|
||||
<button class="btn mx-1">
|
||||
<font-awesome-icon icon="circle-plus" @click="showCreateGroupModal = true" />
|
||||
</button>
|
||||
</div>
|
||||
<hr />
|
||||
<!-- Subscriptions card list -->
|
||||
<div class="pp-subs-cards">
|
||||
<!-- channel info card -->
|
||||
<div efy_card class="pp-subs-card" v-for="subscription in subscriptions" :key="subscription.url">
|
||||
<div v-for="subscription in filteredSubscriptions" :key="subscription.url" efy_card class="pp-subs-card">
|
||||
<router-link :to="subscription.url" class="pp-import-channel flex font-bold">
|
||||
<img :src="subscription.avatar" width="48" height="48" />
|
||||
<span class="mx-2" v-text="subscription.name" />
|
||||
</router-link>
|
||||
<!-- (un)subscribe btn -->
|
||||
<button
|
||||
@click="handleButton(subscription)"
|
||||
v-t="`actions.${subscription.subscribed ? 'unsubscribe' : 'subscribe'}`"
|
||||
class="btn mt-2 w-full"
|
||||
@click="handleButton(subscription)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ModalComponent v-if="showCreateGroupModal" @close="showCreateGroupModal = !showCreateGroupModal">
|
||||
<h2 v-t="'actions.create_group'" />
|
||||
<div class="flex flex-col">
|
||||
<input v-model="newGroupName" class="input my-4" type="text" :placeholder="$t('actions.group_name')" />
|
||||
<button v-t="'actions.create_group'" class="btn ml-auto w-max" @click="createGroup()" />
|
||||
</div>
|
||||
</ModalComponent>
|
||||
|
||||
<ModalComponent v-if="showEditGroupModal" @close="showEditGroupModal = false">
|
||||
<div class="mb-5 mt-3 flex justify-between">
|
||||
<input v-model="editedGroupName" type="text" class="input" />
|
||||
<button v-t="'actions.okay'" class="btn" :placeholder="$t('actions.group_name')" @click="editGroupName()" />
|
||||
</div>
|
||||
<div class="mb-2 mt-3 flex flex-col overflow-y-scroll" style="height: 300rem">
|
||||
<div v-for="subscription in subscriptions" :key="subscription.name">
|
||||
<div class="mr-3 flex justify-between">
|
||||
<span>{{ subscription.name }}</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="checkbox"
|
||||
:checked="selectedGroup.channels.includes(subscription.url.substr(-11))"
|
||||
@change="checkedChange(subscription)"
|
||||
/>
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
</div>
|
||||
</ModalComponent>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@ -34,25 +105,71 @@
|
||||
}
|
||||
.pp-subs-card :is(a, span) {
|
||||
-webkit-text-fill-color: var(--efy_text) !important;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.pp-subs-card button {
|
||||
margin-bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.selected {
|
||||
}
|
||||
.m0c {
|
||||
gap: var(--efy_gap0);
|
||||
}
|
||||
.m0c :is(button, [role="button"]) {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import ModalComponent from "./ModalComponent.vue";
|
||||
|
||||
export default {
|
||||
components: { ModalComponent },
|
||||
data() {
|
||||
return {
|
||||
subscriptions: [],
|
||||
selectedGroup: {
|
||||
groupName: "",
|
||||
channels: [],
|
||||
},
|
||||
channelGroups: [],
|
||||
showCreateGroupModal: false,
|
||||
showEditGroupModal: false,
|
||||
newGroupName: "",
|
||||
editedGroupName: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
filteredSubscriptions(_this) {
|
||||
return _this.selectedGroup.groupName == ""
|
||||
? _this.subscriptions
|
||||
: _this.subscriptions.filter(channel => _this.selectedGroup.channels.includes(channel.url.substr(-11)));
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetchSubscriptions().then(json => {
|
||||
this.subscriptions = json;
|
||||
this.subscriptions.forEach(subscription => (subscription.subscribed = true));
|
||||
});
|
||||
|
||||
this.channelGroups.push(this.selectedGroup);
|
||||
|
||||
if (!window.db) return;
|
||||
const cursor = this.getChannelGroupsCursor();
|
||||
cursor.onsuccess = e => {
|
||||
const cursor = e.target.result;
|
||||
if (cursor) {
|
||||
const group = cursor.value;
|
||||
this.channelGroups.push({
|
||||
groupName: group.groupName,
|
||||
channels: JSON.parse(group.channels),
|
||||
});
|
||||
cursor.continue();
|
||||
}
|
||||
};
|
||||
},
|
||||
activated() {
|
||||
document.title = "Subscriptions - Piped";
|
||||
@ -91,7 +208,6 @@ export default {
|
||||
},
|
||||
exportHandler() {
|
||||
const subscriptions = [];
|
||||
|
||||
this.subscriptions.forEach(subscription => {
|
||||
subscriptions.push({
|
||||
url: "https://www.youtube.com" + subscription.url,
|
||||
@ -99,15 +215,76 @@ export default {
|
||||
service_id: 0,
|
||||
});
|
||||
});
|
||||
|
||||
const json = JSON.stringify({
|
||||
app_version: "",
|
||||
app_version_int: 0,
|
||||
subscriptions: subscriptions,
|
||||
});
|
||||
|
||||
this.download(json, "subscriptions.json", "application/json");
|
||||
},
|
||||
selectGroup(group) {
|
||||
this.selectedGroup = group;
|
||||
this.editedGroupName = group.groupName;
|
||||
},
|
||||
createGroup() {
|
||||
if (!this.newGroupName || this.channelGroups.some(group => group.groupName == this.newGroupName)) return;
|
||||
|
||||
const newGroup = {
|
||||
groupName: this.newGroupName,
|
||||
channels: [],
|
||||
};
|
||||
this.channelGroups.push(newGroup);
|
||||
this.createOrUpdateChannelGroup(newGroup);
|
||||
|
||||
this.newGroupName = "";
|
||||
|
||||
this.showCreateGroupModal = false;
|
||||
},
|
||||
editGroupName() {
|
||||
const oldGroupName = this.selectedGroup.groupName;
|
||||
const newGroupName = this.editedGroupName;
|
||||
|
||||
// the group mustn't yet exist and the name can't be empty
|
||||
if (!newGroupName || newGroupName == oldGroupName) return;
|
||||
if (this.channelGroups.some(group => group.groupName == newGroupName)) return;
|
||||
|
||||
// create a new group with the same info and delete the old one
|
||||
this.selectedGroup.groupName = newGroupName;
|
||||
this.createOrUpdateChannelGroup(this.selectedGroup);
|
||||
this.deleteChannelGroup(oldGroupName);
|
||||
|
||||
this.showEditGroupModal = false;
|
||||
},
|
||||
deleteGroup(group) {
|
||||
this.deleteChannelGroup(group.groupName);
|
||||
this.channelGroups = this.channelGroups.filter(g => g != group);
|
||||
this.selectedGroup = this.channelGroups[0];
|
||||
},
|
||||
checkedChange(subscription) {
|
||||
const channelId = subscription.url.substr(-11);
|
||||
this.selectedGroup.channels = this.selectedGroup.channels.includes(channelId)
|
||||
? this.selectedGroup.channels.filter(channel => channel != channelId)
|
||||
: this.selectedGroup.channels.concat(channelId);
|
||||
this.createOrUpdateChannelGroup(this.selectedGroup);
|
||||
},
|
||||
async importGroupsHandler() {
|
||||
const files = this.$refs.fileSelector.files;
|
||||
for (let file of files) {
|
||||
const groups = JSON.parse(await file.text()).groups;
|
||||
for (let group of groups) {
|
||||
this.createOrUpdateChannelGroup(group);
|
||||
this.channelGroups.push(group);
|
||||
}
|
||||
}
|
||||
},
|
||||
exportGroupsHandler() {
|
||||
const json = {
|
||||
format: "Piped",
|
||||
version: 1,
|
||||
groups: this.channelGroups.slice(1),
|
||||
};
|
||||
this.download(JSON.stringify(json), "channel_groups.json", "application/json");
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
28
src/components/ToastComponent.vue
Normal file
28
src/components/ToastComponent.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<div class="toast">
|
||||
<slot />
|
||||
<button v-t="'actions.dismiss'" @click="dismiss" class="m-0 mt-[10rem]" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
emits: ["dismissed"],
|
||||
methods: {
|
||||
dismiss() {
|
||||
this.$emit("dismissed");
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.toast {
|
||||
@apply flex flex-col justify-center fixed top-[15rem] right-[15rem] min-w-max z-9999;
|
||||
background: var(--efy_text2);
|
||||
color: var(--efy_text);
|
||||
padding: 15rem;
|
||||
border-radius: var(--efy_radius);
|
||||
border: var(--efy_border);
|
||||
}
|
||||
</style>
|
@ -1,15 +1,17 @@
|
||||
<template>
|
||||
<div class="video-grid">
|
||||
<LoadingIndicatorPage :show-content="videos.length != 0" class="video-grid mt-[15rem]">
|
||||
<VideoItem v-for="video in videos" :key="video.url" :item="video" height="118" width="210" />
|
||||
</div>
|
||||
</LoadingIndicatorPage>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LoadingIndicatorPage from "./LoadingIndicatorPage.vue";
|
||||
import VideoItem from "./VideoItem.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VideoItem,
|
||||
LoadingIndicatorPage,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -23,21 +25,15 @@ export default {
|
||||
this.fetchTrending(region).then(videos => {
|
||||
this.videos = videos;
|
||||
this.updateWatched(this.videos);
|
||||
this.fetchDeArrowContent(this.videos);
|
||||
});
|
||||
},
|
||||
activated() {
|
||||
document.title = this.$t("titles.trending") + " - Piped";
|
||||
if (this.videos.length > 0) this.updateWatched(this.videos);
|
||||
if (this.$route.path == "/") {
|
||||
switch (this.getPreferenceString("homepage", "trending")) {
|
||||
case "trending":
|
||||
break;
|
||||
case "feed":
|
||||
this.$router.push("/feed");
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
let homepage = this.getHomePage(this);
|
||||
if (homepage !== undefined) this.$router.push(homepage);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<div v-if="showVideo" class="efy_trans_filter">
|
||||
<div v-if="showVideo" class="video-card efy_trans_filter efy_shadow_trans">
|
||||
<!-- EFY-->
|
||||
<router-link
|
||||
class="video_item_link"
|
||||
:to="{
|
||||
path: '/watch',
|
||||
query: {
|
||||
@ -9,26 +11,61 @@
|
||||
...(index >= 0 && { index: index + 1 }),
|
||||
},
|
||||
}"
|
||||
class="video_item_link"
|
||||
>
|
||||
<img
|
||||
class="w-full"
|
||||
:src="item.thumbnail"
|
||||
:alt="item.title"
|
||||
:src="thumbnail"
|
||||
:alt="title"
|
||||
:class="{ 'shorts-img': item.isShort }"
|
||||
class="thumbnail"
|
||||
loading="lazy"
|
||||
/>
|
||||
<p class="pp-video-card-title my-2 overflow-hidden flex link" :title="item.title" v-text="item.title" />
|
||||
<!-- progress bar -->
|
||||
<div
|
||||
v-if="item.watched && item.duration > 0"
|
||||
class="relative h-1 w-full"
|
||||
style="
|
||||
height: 4rem;
|
||||
background: rgba(255, 255, 255, 0.067);
|
||||
bottom: 8px;
|
||||
border-radius: 0px;
|
||||
box-shadow: 0 -5rem 10rem #0005;
|
||||
backdrop-filter: blur(24px);
|
||||
"
|
||||
>
|
||||
<div
|
||||
class="absolute bottom-0 left-0"
|
||||
:style="{ width: `clamp(0%, ${(item.currentTime / item.duration) * 100}%, 100%` }"
|
||||
style="
|
||||
height: 4rem;
|
||||
background: var(--efy_color);
|
||||
border-radius: 0 var(--efy_radius0) var(--efy_radius0) 0;
|
||||
box-shadow: 3rem 0 5rem #0005;
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center h-[44rem] overflow-hidden">
|
||||
<p v-text="title" class="pp-video-card-title" />
|
||||
</div>
|
||||
</router-link>
|
||||
|
||||
<div class="pp-video-card-buttons">
|
||||
<button v-if="item.duration > 0" v-text="timeFormat(item.duration)" tabindex="-1" />
|
||||
<button v-if="item.views >= 0" tabindex="-1">
|
||||
<font-awesome-icon icon="eye" />
|
||||
<span class="pl-0.5" v-text="`${numberFormat(item.views)}`" />
|
||||
<button
|
||||
v-if="item.duration > 0"
|
||||
v-text="timeFormat(item.duration)"
|
||||
class="efy_shadow_trans efy_shadow_button_off efy_button_text_off"
|
||||
tabindex="-1"
|
||||
/>
|
||||
<button
|
||||
v-if="item.views >= 0"
|
||||
class="efy_shadow_trans efy_shadow_button_off efy_button_text_off"
|
||||
tabindex="-1"
|
||||
>
|
||||
<font-awesome-icon icon="eye" style="margin-right: 5rem" />
|
||||
<span v-text="`${numberFormat(item.views)}`" />
|
||||
</button>
|
||||
<router-link
|
||||
class="btn"
|
||||
class="btn efy_shadow_trans efy_shadow_button_off efy_button_text_off"
|
||||
role="button"
|
||||
:to="{
|
||||
path: '/watch',
|
||||
query: {
|
||||
@ -43,45 +80,65 @@
|
||||
>
|
||||
<font-awesome-icon icon="headphones" />
|
||||
</router-link>
|
||||
<button v-if="authenticated" :title="$t('actions.add_to_playlist')" @click="showModal = !showModal">
|
||||
<button
|
||||
:title="$t('actions.add_to_playlist')"
|
||||
@click="showModal = !showModal"
|
||||
class="btn efy_shadow_trans efy_shadow_button_off efy_button_text_off"
|
||||
>
|
||||
<font-awesome-icon icon="circle-plus" />
|
||||
</button>
|
||||
<button
|
||||
v-if="admin"
|
||||
:title="$t('actions.remove_from_playlist')"
|
||||
ref="removeButton"
|
||||
@click="removeVideo(item.url.substr(-11))"
|
||||
:title="$t('actions.remove_from_playlist')"
|
||||
class="efy_shadow_trans efy_shadow_button_off efy_button_text_off"
|
||||
@click="showConfirmRemove = true"
|
||||
>
|
||||
<font-awesome-icon icon="circle-minus" />
|
||||
</button>
|
||||
<button v-if="item.uploadedDate" class="pl-0.5" v-text="item.uploadedDate" tabindex="-1" />
|
||||
<ConfirmModal
|
||||
v-if="showConfirmRemove"
|
||||
:message="$t('actions.delete_playlist_video_confirm')"
|
||||
@close="showConfirmRemove = false"
|
||||
@confirm="removeVideo(item.url.substr(-11))"
|
||||
/>
|
||||
<PlaylistAddModal
|
||||
v-if="showModal"
|
||||
:video-id="item.url.substr(-11)"
|
||||
:video-info="item"
|
||||
@close="showModal = !showModal"
|
||||
/>
|
||||
<button
|
||||
v-if="item.uploaded > 0"
|
||||
class="efy_shadow_trans efy_shadow_button_off efy_button_text_off"
|
||||
v-text="timeAgo(item.uploaded)"
|
||||
/>
|
||||
<button v-else-if="item.uploadedDate" v-text="item.uploadedDate" tabindex="-1" />
|
||||
<button class="pp-color" v-if="item.isShort" v-t="'video.shorts'" tabindex="-1" />
|
||||
<button v-else-if="item.duration < 0" v-t="'video.live'" class="pp-color" tabindex="-1" />
|
||||
<button v-if="item.watched" v-t="'video.watched'" class="pp-color" tabindex="-1" />
|
||||
</div>
|
||||
|
||||
<router-link
|
||||
:to="item.uploaderUrl"
|
||||
class="pp-video-card-channel"
|
||||
v-if="item.uploaderUrl && item.uploaderName && !hideChannel"
|
||||
:to="item.uploaderUrl"
|
||||
:title="item.uploaderName"
|
||||
class="pp-video-card-channel"
|
||||
>
|
||||
<img
|
||||
v-if="item.uploaderAvatar"
|
||||
:src="item.uploaderAvatar"
|
||||
loading="lazy"
|
||||
:alt="item.uploaderName"
|
||||
class="mt-0.5 w-36rem h-36rem"
|
||||
class="mt-0.5 w-36rem h-36rem efy_shadow_trans efy_shadow_button_off"
|
||||
width="36"
|
||||
height="36"
|
||||
/>
|
||||
|
||||
<div class="pp-text" title="item.uploaderName">
|
||||
<div class="pp-text efy_shadow_trans efy_shadow_button_off">
|
||||
<span v-text="item.uploaderName" />
|
||||
<font-awesome-icon class="ml-1.5" v-if="item.uploaderVerified" icon="check" />
|
||||
</div>
|
||||
</router-link>
|
||||
</div>
|
||||
<PlaylistAddModal v-if="showModal" :video-id="video.url.substr(-11)" @close="showModal = !showModal" />
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@ -95,8 +152,10 @@
|
||||
|
||||
<script>
|
||||
import PlaylistAddModal from "./PlaylistAddModal.vue";
|
||||
import ConfirmModal from "./ConfirmModal.vue";
|
||||
|
||||
export default {
|
||||
components: { PlaylistAddModal, ConfirmModal },
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
@ -115,34 +174,32 @@ export default {
|
||||
playlistId: { type: String, default: null },
|
||||
admin: { type: Boolean, default: false },
|
||||
},
|
||||
emits: ["remove"],
|
||||
data() {
|
||||
return {
|
||||
showModal: false,
|
||||
showVideo: true,
|
||||
showConfirmRemove: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
return this.item.dearrow?.titles[0]?.title ?? this.item.title;
|
||||
},
|
||||
thumbnail() {
|
||||
return this.item.dearrow?.thumbnails[0]?.thumbnail ?? this.item.thumbnail;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.shouldShowVideo();
|
||||
},
|
||||
methods: {
|
||||
removeVideo() {
|
||||
if (confirm(this.$t("actions.delete_playlist_video_confirm"))) {
|
||||
this.$refs.removeButton.disabled = true;
|
||||
this.fetchJson(this.authApiUrl() + "/user/playlists/remove", null, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
playlistId: this.playlistId,
|
||||
index: this.index,
|
||||
}),
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}).then(json => {
|
||||
if (json.error) alert(json.error);
|
||||
else this.$emit("remove");
|
||||
});
|
||||
}
|
||||
this.$refs.removeButton.disabled = true;
|
||||
this.removeVideoFromPlaylist(this.playlistId, this.index).then(json => {
|
||||
if (json.error) alert(json.error);
|
||||
else this.$emit("remove");
|
||||
});
|
||||
},
|
||||
shouldShowVideo() {
|
||||
if (!this.isFeed || !this.getPreferenceBoolean("hideWatched", false)) return;
|
||||
@ -158,6 +215,5 @@ export default {
|
||||
};
|
||||
},
|
||||
},
|
||||
components: { PlaylistAddModal },
|
||||
};
|
||||
</script>
|
||||
|
@ -2,15 +2,49 @@
|
||||
<div
|
||||
ref="container"
|
||||
data-shaka-player-container
|
||||
class="w-full max-h-screen flex justify-center efy_trans_filter_off"
|
||||
class="relative max-h-screen w-full flex justify-center efy_trans_filter_off"
|
||||
:class="{ 'player-container': !isEmbed }"
|
||||
>
|
||||
<video ref="videoEl" class="w-full" data-shaka-player :autoplay="shouldAutoPlay" :loop="selectedAutoLoop" />
|
||||
<span
|
||||
id="preview-container"
|
||||
ref="previewContainer"
|
||||
class="absolute bottom-0 z-[2000] mb-[3.5%] hidden flex-col items-center"
|
||||
>
|
||||
<canvas id="preview" ref="preview" style="border-radius: var(--efy_radius0)" />
|
||||
<span
|
||||
class="w-min"
|
||||
style="
|
||||
border-radius: var(--efy_radius0);
|
||||
background: var(--efy_text2);
|
||||
color: var(--efy_text);
|
||||
padding: 3rem 6rem;
|
||||
"
|
||||
v-text="timeFormat(currentTime)"
|
||||
/>
|
||||
</span>
|
||||
<button
|
||||
v-if="inSegment"
|
||||
class="skip-segment-button"
|
||||
type="button"
|
||||
:aria-label="$t('actions.skip_segment')"
|
||||
aria-pressed="false"
|
||||
@click="onClickSkipSegment"
|
||||
>
|
||||
<span v-t="'actions.skip_segment'" />
|
||||
<i class="material-icons-round">skip_next</i>
|
||||
</button>
|
||||
<span
|
||||
v-if="error > 0"
|
||||
v-t="{ path: 'player.failed', args: [error] }"
|
||||
class="absolute top-8 rounded bg-black/80 p-2 text-lg backdrop-blur-sm"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import("shaka-player/dist/controls.css");
|
||||
import "shaka-player/dist/controls.css";
|
||||
import { parseTimeParam } from "@/utils/Misc";
|
||||
const shaka = import("shaka-player/dist/shaka-player.ui.js");
|
||||
if (!window.muxjs) {
|
||||
import("mux.js").then(muxjs => {
|
||||
@ -27,14 +61,6 @@ export default {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
playlist: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
},
|
||||
sponsors: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
@ -45,12 +71,17 @@ export default {
|
||||
selectedAutoLoop: Boolean,
|
||||
isEmbed: Boolean,
|
||||
},
|
||||
emits: ["timeupdate"],
|
||||
emits: ["timeupdate", "ended", "navigateNext"],
|
||||
data() {
|
||||
return {
|
||||
lastUpdate: new Date().getTime(),
|
||||
initialSeekComplete: false,
|
||||
destroying: false,
|
||||
inSegment: false,
|
||||
isHoveringTimebar: false,
|
||||
currentTime: 0,
|
||||
seekbarPadding: 2,
|
||||
error: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -88,7 +119,7 @@ export default {
|
||||
this.hotkeysPromise.then(() => {
|
||||
var self = this;
|
||||
this.$hotkeys(
|
||||
"f,m,j,k,l,c,space,up,down,left,right,0,1,2,3,4,5,6,7,8,9,shift+n,shift+,,shift+.",
|
||||
"f,m,j,k,l,c,space,up,down,left,right,0,1,2,3,4,5,6,7,8,9,shift+n,shift+,,shift+.,alt+p,return,.,,",
|
||||
function (e, handler) {
|
||||
const videoEl = self.$refs.videoEl;
|
||||
switch (handler.key) {
|
||||
@ -175,7 +206,7 @@ export default {
|
||||
e.preventDefault();
|
||||
break;
|
||||
case "shift+n":
|
||||
self.navigateNext();
|
||||
self.$emit("navigateNext");
|
||||
e.preventDefault();
|
||||
break;
|
||||
case "shift+,":
|
||||
@ -184,6 +215,22 @@ export default {
|
||||
case "shift+.":
|
||||
self.$player.trickPlay(Math.min(videoEl.playbackRate + 0.25, 2));
|
||||
break;
|
||||
case "alt+p":
|
||||
document.pictureInPictureElement
|
||||
? document.exitPictureInPicture()
|
||||
: videoEl.requestPictureInPicture();
|
||||
break;
|
||||
case "return":
|
||||
self.skipSegment(videoEl);
|
||||
break;
|
||||
case ".":
|
||||
videoEl.currentTime += 0.04;
|
||||
e.preventDefault();
|
||||
break;
|
||||
case ",":
|
||||
videoEl.currentTime -= 0.04;
|
||||
e.preventDefault();
|
||||
break;
|
||||
}
|
||||
},
|
||||
);
|
||||
@ -199,6 +246,8 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async loadVideo() {
|
||||
this.updateSponsors();
|
||||
|
||||
const component = this;
|
||||
const videoEl = this.$refs.videoEl;
|
||||
|
||||
@ -207,26 +256,9 @@ export default {
|
||||
const time = this.$route.query.t ?? this.$route.query.start;
|
||||
|
||||
if (time) {
|
||||
let start = 0;
|
||||
if (/^[\d]*$/g.test(time)) {
|
||||
start = time;
|
||||
} else {
|
||||
const hours = /([\d]*)h/gi.exec(time)?.[1];
|
||||
const minutes = /([\d]*)m/gi.exec(time)?.[1];
|
||||
const seconds = /([\d]*)s/gi.exec(time)?.[1];
|
||||
if (hours) {
|
||||
start += parseInt(hours) * 60 * 60;
|
||||
}
|
||||
if (minutes) {
|
||||
start += parseInt(minutes) * 60;
|
||||
}
|
||||
if (seconds) {
|
||||
start += parseInt(seconds);
|
||||
}
|
||||
}
|
||||
videoEl.currentTime = start;
|
||||
videoEl.currentTime = parseTimeParam(time);
|
||||
this.initialSeekComplete = true;
|
||||
} else if (window.db) {
|
||||
} else if (window.db && this.getPreferenceBoolean("watchHistory", false)) {
|
||||
var tx = window.db.transaction("watch_history", "readonly");
|
||||
var store = tx.objectStore("watch_history");
|
||||
var request = store.get(this.video.id);
|
||||
@ -256,9 +288,7 @@ export default {
|
||||
|
||||
const MseSupport = window.MediaSource !== undefined;
|
||||
|
||||
const lbry = this.getPreferenceBoolean("disableLBRY", false)
|
||||
? null
|
||||
: this.video.videoStreams.filter(stream => stream.quality === "LBRY")[0];
|
||||
const lbry = null;
|
||||
|
||||
var uri;
|
||||
var mime;
|
||||
@ -268,9 +298,10 @@ export default {
|
||||
mime = "application/x-mpegURL";
|
||||
} else if (this.video.audioStreams.length > 0 && !lbry && MseSupport) {
|
||||
if (!this.video.dash) {
|
||||
const dash = (
|
||||
await import("@/utils/DashUtils.js").then(mod => mod.default)
|
||||
).generate_dash_file_from_formats(streams, this.video.duration);
|
||||
const dash = (await import("../utils/DashUtils.js")).generate_dash_file_from_formats(
|
||||
streams,
|
||||
this.video.duration,
|
||||
);
|
||||
|
||||
uri = "data:application/dash+xml;charset=utf-8;base64," + btoa(dash);
|
||||
} else {
|
||||
@ -306,7 +337,7 @@ export default {
|
||||
uri = this.video.hls;
|
||||
mime = "application/x-mpegURL";
|
||||
} else {
|
||||
uri = this.video.videoStreams.filter(stream => stream.codec == null).slice(-1)[0].url;
|
||||
uri = this.video.videoStreams.findLast(stream => stream.codec == null).url;
|
||||
mime = "video/mp4";
|
||||
}
|
||||
|
||||
@ -356,22 +387,19 @@ export default {
|
||||
else this.setPlayerAttrs(this.$player, videoEl, uri, mime, this.$shaka);
|
||||
|
||||
if (noPrevPlayer) {
|
||||
videoEl.addEventListener("loadeddata", () => {
|
||||
if (document.pictureInPictureElement) videoEl.requestPictureInPicture();
|
||||
});
|
||||
videoEl.addEventListener("timeupdate", () => {
|
||||
const time = videoEl.currentTime;
|
||||
this.$emit("timeupdate", time);
|
||||
this.updateProgressDatabase(time);
|
||||
if (this.sponsors && this.sponsors.segments) {
|
||||
this.sponsors.segments.map(segment => {
|
||||
if (!segment.skipped || this.selectedAutoLoop) {
|
||||
const end = segment.segment[1];
|
||||
if (time >= segment.segment[0] && time < end) {
|
||||
console.log("Skipped segment at " + time);
|
||||
videoEl.currentTime = end;
|
||||
segment.skipped = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
const segment = this.findCurrentSegment(time);
|
||||
this.inSegment = !!segment;
|
||||
if (segment?.autoskip && (!segment.skipped || this.selectedAutoLoop)) {
|
||||
this.skipSegment(videoEl, segment);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -386,18 +414,27 @@ export default {
|
||||
});
|
||||
|
||||
videoEl.addEventListener("ended", () => {
|
||||
if (
|
||||
!this.selectedAutoLoop &&
|
||||
this.selectedAutoPlay &&
|
||||
(this.playlist?.relatedStreams?.length > 0 || this.video.relatedStreams.length > 0)
|
||||
) {
|
||||
this.navigateNext();
|
||||
}
|
||||
this.$emit("ended");
|
||||
});
|
||||
}
|
||||
|
||||
//TODO: Add sponsors on seekbar: https://github.com/ajayyy/SponsorBlock/blob/e39de9fd852adb9196e0358ed827ad38d9933e29/src/js-components/previewBar.ts#L12
|
||||
},
|
||||
findCurrentSegment(time) {
|
||||
return this.sponsors?.segments?.find(s => time >= s.segment[0] && time < s.segment[1]);
|
||||
},
|
||||
onClickSkipSegment() {
|
||||
const videoEl = this.$refs.videoEl;
|
||||
this.skipSegment(videoEl);
|
||||
},
|
||||
skipSegment(videoEl, segment) {
|
||||
const time = videoEl.currentTime;
|
||||
if (!segment) segment = this.findCurrentSegment(time);
|
||||
if (!segment) return;
|
||||
console.log("Skipped segment at " + time);
|
||||
videoEl.currentTime = segment.segment[1];
|
||||
segment.skipped = true;
|
||||
},
|
||||
setPlayerAttrs(localPlayer, videoEl, uri, mime, shaka) {
|
||||
const url = "/watch?v=" + this.video.id;
|
||||
|
||||
@ -471,8 +508,13 @@ export default {
|
||||
|
||||
this.updateMarkers();
|
||||
|
||||
const event = new Event("playerInit");
|
||||
window.dispatchEvent(event);
|
||||
|
||||
const player = this.$ui.getControls().getPlayer();
|
||||
|
||||
this.setupSeekbarPreview();
|
||||
|
||||
this.$player = player;
|
||||
|
||||
const disableVideo = this.getPreferenceBoolean("listen", false) && !this.video.livestream;
|
||||
@ -483,6 +525,9 @@ export default {
|
||||
manifest: {
|
||||
disableVideo: disableVideo,
|
||||
},
|
||||
streaming: {
|
||||
segmentPrefetchLimit: 10,
|
||||
},
|
||||
});
|
||||
|
||||
const quality = this.getPreferenceNumber("quality", 0);
|
||||
@ -490,70 +535,83 @@ export default {
|
||||
quality > 0 && (this.video.audioStreams.length > 0 || this.video.livestream) && !disableVideo;
|
||||
if (qualityConds) this.$player.configure("abr.enabled", false);
|
||||
|
||||
player.load(uri, 0, mime).then(() => {
|
||||
const isSafari = window.navigator?.vendor?.includes("Apple");
|
||||
player
|
||||
.load(uri, 0, mime)
|
||||
.then(() => {
|
||||
const isSafari = window.navigator?.vendor?.includes("Apple");
|
||||
|
||||
if (!isSafari) {
|
||||
// Set the audio language
|
||||
const prefLang = this.getPreferenceString("hl", "en").substr(0, 2);
|
||||
var lang = "en";
|
||||
for (var l in player.getAudioLanguages()) {
|
||||
if (l == prefLang) {
|
||||
lang = l;
|
||||
return;
|
||||
}
|
||||
}
|
||||
player.selectAudioLanguage(lang);
|
||||
}
|
||||
|
||||
if (qualityConds) {
|
||||
var leastDiff = Number.MAX_VALUE;
|
||||
var bestStream = null;
|
||||
|
||||
var bestAudio = 0;
|
||||
|
||||
const tracks = player
|
||||
.getVariantTracks()
|
||||
.filter(track => track.language == lang || track.language == "und");
|
||||
|
||||
// Choose the best audio stream
|
||||
if (quality >= 480)
|
||||
tracks.forEach(track => {
|
||||
const audioBandwidth = track.audioBandwidth;
|
||||
if (audioBandwidth > bestAudio) bestAudio = audioBandwidth;
|
||||
});
|
||||
|
||||
// Find best matching stream based on resolution and bitrate
|
||||
tracks
|
||||
.sort((a, b) => a.bandwidth - b.bandwidth)
|
||||
.forEach(stream => {
|
||||
if (stream.audioBandwidth < bestAudio) return;
|
||||
|
||||
const diff = Math.abs(quality - stream.height);
|
||||
if (diff < leastDiff) {
|
||||
leastDiff = diff;
|
||||
bestStream = stream;
|
||||
if (!isSafari) {
|
||||
// Set the audio language
|
||||
const prefLang = this.getPreferenceString("hl", "en").substr(0, 2);
|
||||
var lang = "en";
|
||||
for (var l in player.getAudioLanguages()) {
|
||||
if (l == prefLang) {
|
||||
lang = l;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
player.selectAudioLanguage(lang);
|
||||
}
|
||||
|
||||
player.selectVariantTrack(bestStream);
|
||||
}
|
||||
if (qualityConds) {
|
||||
var leastDiff = Number.MAX_VALUE;
|
||||
var bestStream = null;
|
||||
|
||||
this.video.subtitles.map(subtitle => {
|
||||
player.addTextTrackAsync(
|
||||
subtitle.url,
|
||||
subtitle.code,
|
||||
"SUBTITLE",
|
||||
subtitle.mimeType,
|
||||
null,
|
||||
subtitle.name,
|
||||
);
|
||||
var bestAudio = 0;
|
||||
|
||||
const tracks = player
|
||||
.getVariantTracks()
|
||||
.filter(track => track.language == lang || track.language == "und");
|
||||
|
||||
// Choose the best audio stream
|
||||
if (quality >= 480)
|
||||
tracks.forEach(track => {
|
||||
const audioBandwidth = track.audioBandwidth;
|
||||
if (audioBandwidth > bestAudio) bestAudio = audioBandwidth;
|
||||
});
|
||||
|
||||
// Find best matching stream based on resolution and bitrate
|
||||
tracks
|
||||
.sort((a, b) => a.bandwidth - b.bandwidth)
|
||||
.forEach(stream => {
|
||||
if (stream.audioBandwidth < bestAudio) return;
|
||||
|
||||
const diff = Math.abs(quality - stream.height);
|
||||
if (diff < leastDiff) {
|
||||
leastDiff = diff;
|
||||
bestStream = stream;
|
||||
}
|
||||
});
|
||||
|
||||
player.selectVariantTrack(bestStream);
|
||||
}
|
||||
|
||||
this.video.subtitles.map(subtitle => {
|
||||
player.addTextTrackAsync(
|
||||
subtitle.url,
|
||||
subtitle.code,
|
||||
"subtitles",
|
||||
subtitle.mimeType,
|
||||
null,
|
||||
subtitle.name,
|
||||
);
|
||||
});
|
||||
videoEl.volume = this.getPreferenceNumber("volume", 1);
|
||||
const rate = this.getPreferenceNumber("rate", 1);
|
||||
videoEl.playbackRate = rate;
|
||||
videoEl.defaultPlaybackRate = rate;
|
||||
|
||||
const autoDisplayCaptions = this.getPreferenceBoolean("autoDisplayCaptions", false);
|
||||
this.$player.setTextTrackVisibility(autoDisplayCaptions);
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
this.error = e.code;
|
||||
});
|
||||
videoEl.volume = this.getPreferenceNumber("volume", 1);
|
||||
const rate = this.getPreferenceNumber("rate", 1);
|
||||
videoEl.playbackRate = rate;
|
||||
videoEl.defaultPlaybackRate = rate;
|
||||
});
|
||||
|
||||
// expand the player to fullscreen when the fullscreen query equals true
|
||||
if (this.$route.query.fullscreen === "true" && !this.$ui.getControls().isFullScreenEnabled())
|
||||
this.$ui.getControls().toggleFullScreen();
|
||||
},
|
||||
async updateProgressDatabase(time) {
|
||||
// debounce
|
||||
@ -578,29 +636,7 @@ export default {
|
||||
this.$refs.videoEl.currentTime = time;
|
||||
}
|
||||
},
|
||||
navigateNext() {
|
||||
const params = this.$route.query;
|
||||
let url = this.playlist?.relatedStreams?.[this.index]?.url ?? this.video.relatedStreams[0].url;
|
||||
const searchParams = new URLSearchParams();
|
||||
for (var param in params)
|
||||
switch (param) {
|
||||
case "v":
|
||||
case "t":
|
||||
break;
|
||||
case "index":
|
||||
if (this.index < this.playlist.relatedStreams.length) searchParams.set("index", this.index + 1);
|
||||
break;
|
||||
case "list":
|
||||
if (this.index < this.playlist.relatedStreams.length) searchParams.set("list", params.list);
|
||||
break;
|
||||
default:
|
||||
searchParams.set(param, params[param]);
|
||||
break;
|
||||
}
|
||||
const paramStr = searchParams.toString();
|
||||
if (paramStr.length > 0) url += "&" + paramStr;
|
||||
this.$router.push(url);
|
||||
},
|
||||
|
||||
updateMarkers() {
|
||||
const markers = this.$refs.container.querySelector(".shaka-ad-markers");
|
||||
const array = ["to right"];
|
||||
@ -608,38 +644,19 @@ export default {
|
||||
const start = (segment.segment[0] / this.video.duration) * 100;
|
||||
const end = (segment.segment[1] / this.video.duration) * 100;
|
||||
|
||||
var color;
|
||||
switch (segment.category) {
|
||||
case "sponsor":
|
||||
color = "#00d400";
|
||||
break;
|
||||
case "selfpromo":
|
||||
color = "#ffff00";
|
||||
break;
|
||||
case "interaction":
|
||||
color = "#cc00ff";
|
||||
break;
|
||||
case "poi_highlight":
|
||||
color = "#ff1684";
|
||||
break;
|
||||
case "intro":
|
||||
color = "#00ffff";
|
||||
break;
|
||||
case "outro":
|
||||
color = "#0202ed";
|
||||
break;
|
||||
case "preview":
|
||||
color = "#008fd6";
|
||||
break;
|
||||
case "filler":
|
||||
color = "#7300FF";
|
||||
break;
|
||||
case "music_offtopic":
|
||||
color = "#ff9900";
|
||||
break;
|
||||
default:
|
||||
color = "white";
|
||||
}
|
||||
var color = [
|
||||
"sponsor",
|
||||
"selfpromo",
|
||||
"interaction",
|
||||
"poi_highlight",
|
||||
"intro",
|
||||
"outro",
|
||||
"preview",
|
||||
"filler",
|
||||
"music_offtopic",
|
||||
].includes(segment.category)
|
||||
? `var(--spon-seg-${segment.category})`
|
||||
: "var(--spon-seg-default)";
|
||||
|
||||
array.push(`transparent ${start}%`);
|
||||
array.push(`${color} ${start}%`);
|
||||
@ -653,33 +670,133 @@ export default {
|
||||
|
||||
if (markers) markers.style.background = `linear-gradient(${array.join(",")})`;
|
||||
},
|
||||
destroy(hotkeys) {
|
||||
if (this.$ui) {
|
||||
this.$ui.destroy();
|
||||
this.$ui = undefined;
|
||||
this.$player = undefined;
|
||||
}
|
||||
if (this.$player) {
|
||||
this.$player.destroy();
|
||||
this.$player = undefined;
|
||||
}
|
||||
if (hotkeys) this.$hotkeys?.unbind();
|
||||
this.$refs.container?.querySelectorAll("div").forEach(node => node.remove());
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
sponsors() {
|
||||
updateSponsors() {
|
||||
if (this.getPreferenceBoolean("showMarkers", true)) {
|
||||
this.shakaPromise.then(() => {
|
||||
this.updateMarkers();
|
||||
});
|
||||
}
|
||||
},
|
||||
setupSeekbarPreview() {
|
||||
if (!this.video.previewFrames) return;
|
||||
let seekBar = document.querySelector(".shaka-seek-bar");
|
||||
// load the thumbnail preview when the user moves over the seekbar
|
||||
seekBar.addEventListener("mousemove", e => {
|
||||
this.isHoveringTimebar = true;
|
||||
const position = (e.offsetX / e.target.offsetWidth) * this.video.duration;
|
||||
this.showSeekbarPreview(position * 1000);
|
||||
});
|
||||
// hide the preview when the user stops hovering the seekbar
|
||||
seekBar.addEventListener("mouseout", () => {
|
||||
this.isHoveringTimebar = false;
|
||||
this.$refs.previewContainer.style.display = "none";
|
||||
});
|
||||
},
|
||||
async showSeekbarPreview(position) {
|
||||
const frame = this.getFrame(position);
|
||||
const originalImage = await this.loadImage(frame.url);
|
||||
if (!this.isHoveringTimebar) return;
|
||||
|
||||
const seekBar = document.querySelector(".shaka-seek-bar");
|
||||
const container = this.$refs.previewContainer;
|
||||
const canvas = this.$refs.preview;
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
const offsetX = frame.positionX * frame.frameWidth;
|
||||
const offsetY = frame.positionY * frame.frameHeight;
|
||||
|
||||
canvas.width = frame.frameWidth > 100 ? frame.frameWidth : frame.frameWidth * 2;
|
||||
canvas.height = frame.frameWidth > 100 ? frame.frameHeight : frame.frameHeight * 2;
|
||||
// draw the thumbnail preview into the canvas by cropping only the relevant part
|
||||
ctx.drawImage(
|
||||
originalImage,
|
||||
offsetX,
|
||||
offsetY,
|
||||
frame.frameWidth,
|
||||
frame.frameHeight,
|
||||
0,
|
||||
0,
|
||||
canvas.width,
|
||||
canvas.height,
|
||||
);
|
||||
|
||||
// calculate the thumbnail preview offset and display it
|
||||
const centerOffset = position / this.video.duration / 10;
|
||||
const left = centerOffset - ((0.5 * canvas.width) / seekBar.clientWidth) * 100;
|
||||
const maxLeft =
|
||||
((seekBar.clientWidth - canvas.clientWidth) / seekBar.clientWidth) * 100 - this.seekbarPadding;
|
||||
|
||||
this.currentTime = position / 1000;
|
||||
|
||||
container.style.left = `max(${this.seekbarPadding}%, min(${left}%, ${maxLeft}%))`;
|
||||
container.style.display = "flex";
|
||||
},
|
||||
// ineffective algorithm to find the thumbnail corresponding to the currently hovered position in the video
|
||||
getFrame(position) {
|
||||
let startPosition = 0;
|
||||
const framePage = this.video.previewFrames.at(-1);
|
||||
for (let i = 0; i < framePage.urls.length; i++) {
|
||||
for (let positionY = 0; positionY < framePage.framesPerPageY; positionY++) {
|
||||
for (let positionX = 0; positionX < framePage.framesPerPageX; positionX++) {
|
||||
const endPosition = startPosition + framePage.durationPerFrame;
|
||||
if (position >= startPosition && position <= endPosition) {
|
||||
return {
|
||||
url: framePage.urls[i],
|
||||
positionX: positionX,
|
||||
positionY: positionY,
|
||||
frameWidth: framePage.frameWidth,
|
||||
frameHeight: framePage.frameHeight,
|
||||
};
|
||||
}
|
||||
startPosition = endPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// creates a new image from an URL
|
||||
loadImage(url) {
|
||||
return new Promise(r => {
|
||||
const i = new Image();
|
||||
i.onload = () => r(i);
|
||||
i.src = url;
|
||||
});
|
||||
},
|
||||
destroy(hotkeys) {
|
||||
if (this.$ui && !document.pictureInPictureElement) {
|
||||
this.$ui.destroy();
|
||||
this.$ui = undefined;
|
||||
this.$player = undefined;
|
||||
}
|
||||
if (this.$player) {
|
||||
this.$player.destroy();
|
||||
if (!document.pictureInPictureElement) this.$player = undefined;
|
||||
}
|
||||
if (hotkeys) this.$hotkeys?.unbind();
|
||||
this.$refs.container?.querySelectorAll("div").forEach(node => node.remove());
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--player-base: rgba(255, 255, 255, 0.3);
|
||||
--player-buffered: rgba(255, 255, 255, 0.54);
|
||||
--player-played: rgba(255, 0, 0);
|
||||
|
||||
--spon-seg-sponsor: #00d400;
|
||||
--spon-seg-selfpromo: #ffff00;
|
||||
--spon-seg-interaction: #cc00ff;
|
||||
--spon-seg-poi_highlight: #ff1684;
|
||||
--spon-seg-intro: #00ffff;
|
||||
--spon-seg-outro: #0202ed;
|
||||
--spon-seg-preview: #008fd6;
|
||||
--spon-seg-filler: #7300ff;
|
||||
--spon-seg-music_offtopic: #ff9900;
|
||||
--spon-seg-default: white;
|
||||
}
|
||||
|
||||
.player-container {
|
||||
@apply max-h-75vh min-h-64;
|
||||
background: #000;
|
||||
@ -732,11 +849,15 @@ html .shaka-range-element:focus {
|
||||
.material-icons-round {
|
||||
font-family: "Material Icons Round" !important;
|
||||
}
|
||||
.material-icons-round,
|
||||
.shaka-bottom-controls .material-icons-round,
|
||||
.shaka-current-time {
|
||||
-webkit-text-fill-color: #fff !important;
|
||||
filter: none !important;
|
||||
opacity: 1 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.shaka-bottom-controls .material-icons-round {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.shaka-overflow-menu,
|
||||
.shaka-settings-menu {
|
||||
@ -767,4 +888,17 @@ html .shaka-range-element:focus {
|
||||
.shaka-controls-container {
|
||||
border-radius: var(--efy_radius) !important;
|
||||
}
|
||||
|
||||
.skip-segment-button {
|
||||
z-index: 1000;
|
||||
position: absolute;
|
||||
transform: translate(0, -50%);
|
||||
top: 50%;
|
||||
right: 0;
|
||||
border-right: 0;
|
||||
border-radius: var(--efy_radius) 0 0 var(--efy_radius);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
29
src/components/WatchOnButton.vue
Normal file
29
src/components/WatchOnButton.vue
Normal file
@ -0,0 +1,29 @@
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
link: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
platform: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "YouTube",
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template v-if="getPreferenceBoolean('showWatchOnYouTube', false)">
|
||||
<a
|
||||
:href="link"
|
||||
role="button"
|
||||
class="pp-square flex items-center justify-center"
|
||||
:aria-label="'Watch on Odysee'"
|
||||
:title="`${$t('player.watch_on')}${platform}`"
|
||||
>
|
||||
<font-awesome-icon class="mx-1.5" :icon="['fab', platform.toLowerCase()]" />
|
||||
</a>
|
||||
</template>
|
||||
</template>
|
@ -1,24 +0,0 @@
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
link: String,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template v-if="this.getPreferenceBoolean('showWatchOnYouTube', false)">
|
||||
<a :href="link" class="pp-watch-onyt-btn btn" role="button" :title="$t('player.watch_on') + 'YouTube'">
|
||||
<font-awesome-icon class="mx-1.5" :icon="['fab', 'youtube']" />
|
||||
</a>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.pp-watch-onyt-btn {
|
||||
display: flex;
|
||||
margin-left: var(--efy_gap0);
|
||||
align-items: center;
|
||||
gap: 5rem;
|
||||
}
|
||||
</style>
|
@ -1,43 +1,48 @@
|
||||
<template>
|
||||
<div v-if="video && isEmbed" class="absolute top-0 left-0 h-full w-full bg-black z-50">
|
||||
<div v-if="video && isEmbed" class="absolute left-0 top-0 z-50 h-full w-full bg-black">
|
||||
<VideoPlayer
|
||||
ref="videoPlayer"
|
||||
:video="video"
|
||||
:sponsors="sponsors"
|
||||
:playlist="playlist"
|
||||
:index="index"
|
||||
:selected-auto-play="false"
|
||||
:selected-auto-loop="selectedAutoLoop"
|
||||
:is-embed="isEmbed"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="video && !isEmbed" class="w-full">
|
||||
<LoadingIndicatorPage :show-content="video && !isEmbed" class="w-full mt-[15rem]">
|
||||
<ErrorHandler v-if="video && video.error" :message="video.message" :error="video.error" />
|
||||
<Transition>
|
||||
<ToastComponent v-if="shouldShowToast" @dismissed="dismiss">
|
||||
<i18n-t keypath="info.next_video_countdown">{{ counter }}</i18n-t>
|
||||
</ToastComponent>
|
||||
</Transition>
|
||||
|
||||
<div v-show="!video.error">
|
||||
<div :class="isMobile ? 'flex-col' : 'flex'">
|
||||
<VideoPlayer
|
||||
ref="videoPlayer"
|
||||
:video="video"
|
||||
:sponsors="sponsors"
|
||||
:playlist="playlist"
|
||||
:index="index"
|
||||
:selected-auto-play="selectedAutoPlay"
|
||||
:selected-auto-loop="selectedAutoLoop"
|
||||
@timeupdate="onTimeUpdate"
|
||||
/>
|
||||
<keep-alive>
|
||||
<VideoPlayer
|
||||
ref="videoPlayer"
|
||||
:video="video"
|
||||
:sponsors="sponsors"
|
||||
:selected-auto-play="selectedAutoPlay"
|
||||
:selected-auto-loop="selectedAutoLoop"
|
||||
@timeupdate="onTimeUpdate"
|
||||
@ended="onVideoEnded"
|
||||
@navigate-next="navigateNext"
|
||||
/>
|
||||
</keep-alive>
|
||||
<ChaptersBar
|
||||
:mobileLayout="isMobile"
|
||||
v-if="video?.chapters?.length > 0 && showChapters"
|
||||
:mobile-layout="isMobile"
|
||||
:chapters="video.chapters"
|
||||
:player-position="currentTime"
|
||||
@seek="navigate"
|
||||
/>
|
||||
</div>
|
||||
<!-- video title -->
|
||||
<div class="pp-video-title font-bold mt-2 text-2xl break-words" v-text="video.title" />
|
||||
<div class="pp-bellow-video flex flex-wrap mt-3 mb-3">
|
||||
<div class="pp-video-title mt-2 break-words text-2xl font-bold" v-text="video.title" />
|
||||
<div class="pp-bellow-video mb-3 mt-3 flex flex-wrap">
|
||||
<!-- views / date -->
|
||||
<div class="flex flex-auto">
|
||||
<span v-t="{ path: 'video.views', args: { views: addCommas(video.views) } }" />
|
||||
@ -48,11 +53,11 @@
|
||||
<div class="pp-likes flex children:mr-2">
|
||||
<template v-if="video.likes >= 0">
|
||||
<div class="flex items-center">
|
||||
<div class="i-fa-solid:thumbs-up" />
|
||||
<div class="i-fa6-solid:thumbs-up" />
|
||||
<strong class="ml-1" v-text="addCommas(video.likes)" />
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<div class="i-fa-solid:thumbs-down" />
|
||||
<div class="i-fa6-solid:thumbs-down" />
|
||||
<strong class="ml-1" v-text="video.dislikes >= 0 ? addCommas(video.dislikes) : '?'" />
|
||||
</div>
|
||||
</template>
|
||||
@ -72,54 +77,29 @@
|
||||
video.uploader
|
||||
}}</router-link>
|
||||
<!-- Verified Badge -->
|
||||
<font-awesome-icon class="ml-1" v-if="video.uploaderVerified" icon="check" />
|
||||
<font-awesome-icon v-if="video.uploaderVerified" class="ml-1" icon="check" />
|
||||
</div>
|
||||
<div class="pp-watch-buttons">
|
||||
<!-- Subscribe button -->
|
||||
<button
|
||||
class="btn"
|
||||
@click="subscribeHandler"
|
||||
v-t="{
|
||||
path: `actions.${subscribed ? 'unsubscribe' : 'subscribe'}`,
|
||||
args: { count: numberFormat(video.uploaderSubscriberCount) },
|
||||
}"
|
||||
class="btn"
|
||||
@click="subscribeHandler"
|
||||
/>
|
||||
<!-- RSS Feed button -->
|
||||
<a
|
||||
aria-label="RSS feed"
|
||||
title="RSS feed"
|
||||
role="button"
|
||||
v-if="video.uploaderUrl"
|
||||
:href="`${apiUrl()}/feed/unauthenticated/rss?channels=${video.uploaderUrl.split('/')[2]}`"
|
||||
target="_blank"
|
||||
class="btn flex-col"
|
||||
>
|
||||
<font-awesome-icon icon="rss" />
|
||||
</a>
|
||||
<WatchOnYouTubeButton :link="`https://youtu.be/${getVideoId()}`" />
|
||||
<!-- Share Dialog -->
|
||||
<button class="btn" @click="showShareModal = !showShareModal">
|
||||
<i18n-t class="lt-lg:hidden" keypath="actions.share" tag="strong"></i18n-t>
|
||||
<font-awesome-icon class="mx-1.5 ml-1" icon="fa-share" />
|
||||
</button>
|
||||
<!-- LBRY -->
|
||||
<a v-if="video.lbryId" :href="'https://odysee.com/' + video.lbryId" class="btn">
|
||||
<i18n-t keypath="player.watch_on" tag="strong">LBRY</i18n-t>
|
||||
</a>
|
||||
<!-- listen / watch toggle -->
|
||||
<router-link
|
||||
:to="toggleListenUrl"
|
||||
:aria-label="(isListening ? 'Watch ' : 'Listen to ') + video.title"
|
||||
:title="(isListening ? 'Watch ' : 'Listen to ') + video.title"
|
||||
class="btn flex-col"
|
||||
>
|
||||
<font-awesome-icon :icon="isListening ? 'tv' : 'headphones'" />
|
||||
</router-link>
|
||||
<!-- Playlist Add button -->
|
||||
<button class="btn" v-if="authenticated" @click="showModal = !showModal">
|
||||
<button class="btn flex items-center" @click="showModal = !showModal">
|
||||
{{ $t("actions.add_to_playlist") }}<font-awesome-icon class="ml-1" icon="circle-plus" />
|
||||
</button>
|
||||
<PlaylistAddModal v-if="showModal" :video-id="getVideoId()" @close="showModal = !showModal" />
|
||||
<PlaylistAddModal
|
||||
v-if="showModal"
|
||||
:video-id="getVideoId()"
|
||||
:video-info="video"
|
||||
@close="showModal = !showModal"
|
||||
/>
|
||||
<!-- Share Dialog -->
|
||||
<ShareModal
|
||||
v-if="showShareModal"
|
||||
:video-id="getVideoId()"
|
||||
@ -128,59 +108,119 @@
|
||||
:playlist-index="index"
|
||||
@close="showShareModal = !showShareModal"
|
||||
/>
|
||||
<button class="btn flex items-center share-btn" @click="showShareModal = !showShareModal">
|
||||
<font-awesome-icon class="mx-1.5 mr-1" icon="fa-share" />
|
||||
<i18n-t keypath="actions.share" tag="strong"></i18n-t>
|
||||
</button>
|
||||
<!-- YouTube -->
|
||||
<WatchOnButton :link="`https://youtu.be/${getVideoId()}`" />
|
||||
<!-- Odysee -->
|
||||
<WatchOnButton v-if="video.lbryId" platform="Odysee" :link="`https://odysee.com/${video.lbryId}`" />
|
||||
<!-- listen / watch toggle -->
|
||||
<router-link
|
||||
:to="toggleListenUrl"
|
||||
role="button"
|
||||
:aria-label="(isListening ? 'Watch ' : 'Listen to ') + video.title"
|
||||
:title="(isListening ? 'Watch ' : 'Listen to ') + video.title"
|
||||
class="pp-square btn flex items-center"
|
||||
>
|
||||
<font-awesome-icon class="mx-1.5" :icon="isListening ? 'tv' : 'headphones'" />
|
||||
</router-link>
|
||||
<!-- RSS Feed button -->
|
||||
<a
|
||||
v-if="video.uploaderUrl"
|
||||
aria-label="RSS feed"
|
||||
title="RSS feed"
|
||||
role="button"
|
||||
:href="`${apiUrl()}/feed/unauthenticated/rss?channels=${video.uploaderUrl.split('/')[2]}`"
|
||||
target="_blank"
|
||||
class="pp-square btn flex items-center"
|
||||
>
|
||||
<font-awesome-icon class="mx-1.5" icon="rss" />
|
||||
</a>
|
||||
<button class="btn flex items-center gap-1 <md:hidden" @click="downloadCurrentFrame">
|
||||
<i class="i-fa6-solid:download" />{{ $t("actions.download_frame") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<hr class="mb-2" />
|
||||
|
||||
<div
|
||||
v-for="metaInfo in video?.metaInfo ?? []"
|
||||
:key="metaInfo.title"
|
||||
class="btn my-3 flex flex-wrap cursor-default gap-2 px-4 py-2"
|
||||
>
|
||||
<span>{{ metaInfo.description ?? metaInfo.title }}</span>
|
||||
<a v-for="(link, linkIndex) in metaInfo.urls" :key="linkIndex" :href="link" class="underline">{{
|
||||
metaInfo.urlTexts[linkIndex]
|
||||
}}</a>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<div efy_select>
|
||||
<input id="showDesc" type="checkbox" v-model="showDesc" />
|
||||
<label for="showDesc" v-t="'actions.show_description'" />
|
||||
<input id="showComments" type="checkbox" v-model="showComments" @click="toggleComments" />
|
||||
<label for="showComments" v-t="'actions.show_comments'" />
|
||||
<input id="showRecs" type="checkbox" v-model="showRecs" />
|
||||
<label for="showRecs" v-t="'actions.show_recommendations'" />
|
||||
<input id="showDesc" v-model="showDesc" type="checkbox" />
|
||||
<label v-t="'actions.show_description'" for="showDesc" />
|
||||
<input id="showComments" v-model="showComments" type="checkbox" @click="toggleComments" />
|
||||
<label
|
||||
v-text="`${$t('actions.show_comments')} - ${numberFormat(comments?.commentCount)}`"
|
||||
for="showComments"
|
||||
/>
|
||||
<input id="showRecs" v-model="showRecs" type="checkbox" />
|
||||
<label v-t="'actions.show_recommendations'" for="showRecs" />
|
||||
<span v-show="video?.chapters?.length > 0">
|
||||
<input id="showChapters" v-model="showChapters" type="checkbox" />
|
||||
<label v-t="'actions.show_chapters'" class="ml-2" for="showChapters" />
|
||||
</span>
|
||||
<input id="chkAutoLoop" v-model="selectedAutoLoop" type="checkbox" @change="onChange($event)" />
|
||||
<label for="chkAutoLoop" v-text="`${$t('actions.loop_this_video')}`" />
|
||||
<input id="chkAutoPlay" v-model="selectedAutoPlay" type="checkbox" @change="onChange($event)" />
|
||||
<label for="chkAutoPlay" v-text="`${$t('actions.auto_play_next_video')}`" />
|
||||
<span v-show="video?.chapters?.length > 0">
|
||||
<input id="showChapters" type="checkbox" v-model="showChapters" />
|
||||
<label class="ml-2" for="showChapters" v-t="'actions.show_chapters'" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div
|
||||
v-show="showDesc"
|
||||
class="break-words mb-2"
|
||||
v-html="purifyHTML(video.description)"
|
||||
style="border-top: var(--efy_border); margin: 15rem 0; padding: 15rem 0"
|
||||
/>
|
||||
<div
|
||||
v-if="showDesc && sponsors && sponsors.segments"
|
||||
v-text="`${$t('video.sponsor_segments')}: ${sponsors.segments.length}`"
|
||||
/>
|
||||
<template v-if="showDesc">
|
||||
<hr />
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div class="description break-words" v-html="purifiedDescription" />
|
||||
<hr />
|
||||
<div
|
||||
v-if="sponsors && sponsors.segments"
|
||||
v-text="`${$t('video.sponsor_segments')}: ${sponsors.segments.length}`"
|
||||
/>
|
||||
<div v-if="video.category" v-text="`${$t('video.category')}: ${video.category}`" />
|
||||
<div v-text="`${$t('video.license')}: ${video.license}`" />
|
||||
<div class="capitalize" v-text="`${$t('video.visibility')}: ${video.visibility}`" />
|
||||
<hr />
|
||||
<div v-if="video.tags" class="video-tags">
|
||||
<router-link
|
||||
v-for="tag in video.tags"
|
||||
:key="tag"
|
||||
class="line-clamp-1 efy_trans_filter efy_shadow_trans"
|
||||
:to="`/results?search_query=${encodeURIComponent(tag)}`"
|
||||
>{{ tag }}</router-link
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="grid pp-rec-vids">
|
||||
<div class="pp-rec-vids grid">
|
||||
<div v-if="!showComments" class="w-full"></div>
|
||||
<div v-if="!comments" class="">
|
||||
<p class="text-center mt-8" v-t="'comment.loading'"></p>
|
||||
<div v-else-if="!comments">
|
||||
<p v-t="'comment.loading'" class="mt-8 text-center"></p>
|
||||
</div>
|
||||
<div v-else-if="comments.disabled" class="">
|
||||
<p class="text-center mt-8" v-t="'comment.disabled'"></p>
|
||||
<div v-else-if="comments.disabled">
|
||||
<p v-t="'comment.disabled'" class="mt-8 text-center"></p>
|
||||
</div>
|
||||
<div v-else ref="comments" v-show="showComments" class="pp-comments">
|
||||
<div v-else ref="comments" class="pp-comments">
|
||||
<CommentItem
|
||||
v-for="comment in comments.comments"
|
||||
:key="comment.commentId"
|
||||
:comment="comment"
|
||||
:uploader="video.uploader"
|
||||
:video-id="getVideoId()"
|
||||
class="efy_trans_filter"
|
||||
class="efy_trans_filter efy_shadow_trans"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -203,7 +243,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</LoadingIndicatorPage>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -215,7 +255,11 @@ import ChaptersBar from "./ChaptersBar.vue";
|
||||
import PlaylistAddModal from "./PlaylistAddModal.vue";
|
||||
import ShareModal from "./ShareModal.vue";
|
||||
import PlaylistVideos from "./PlaylistVideos.vue";
|
||||
import WatchOnYouTubeButton from "./WatchOnYouTubeButton.vue";
|
||||
import WatchOnButton from "./WatchOnButton.vue";
|
||||
import LoadingIndicatorPage from "./LoadingIndicatorPage.vue";
|
||||
import ToastComponent from "./ToastComponent.vue";
|
||||
import { parseTimeParam } from "@/utils/Misc";
|
||||
import { purifyHTML, rewriteDescription } from "@/utils/HtmlUtils";
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
@ -228,14 +272,14 @@ export default {
|
||||
PlaylistAddModal,
|
||||
ShareModal,
|
||||
PlaylistVideos,
|
||||
WatchOnYouTubeButton,
|
||||
WatchOnButton,
|
||||
LoadingIndicatorPage,
|
||||
ToastComponent,
|
||||
},
|
||||
data() {
|
||||
const smallViewQuery = window.matchMedia("(max-width: 640px)");
|
||||
return {
|
||||
video: {
|
||||
title: "Loading...",
|
||||
},
|
||||
video: null,
|
||||
playlistId: null,
|
||||
playlist: null,
|
||||
index: null,
|
||||
@ -256,6 +300,9 @@ export default {
|
||||
showShareModal: false,
|
||||
isMobile: true,
|
||||
currentTime: 0,
|
||||
shouldShowToast: false,
|
||||
timeoutCounter: null,
|
||||
counter: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -277,6 +324,12 @@ export default {
|
||||
year: "numeric",
|
||||
});
|
||||
},
|
||||
defaultCounter(_this) {
|
||||
return _this.getPreferenceNumber("autoPlayNextCountdown", 5);
|
||||
},
|
||||
purifiedDescription() {
|
||||
return purifyHTML(this.video.description);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// check screen size
|
||||
@ -295,7 +348,7 @@ export default {
|
||||
(async () => {
|
||||
const videoId = this.getVideoId();
|
||||
const instance = this;
|
||||
if (window.db && !this.video.error) {
|
||||
if (window.db && this.getPreferenceBoolean("watchHistory", false) && !this.video.error) {
|
||||
var tx = window.db.transaction("watch_history", "readwrite");
|
||||
var store = tx.objectStore("watch_history");
|
||||
var request = store.get(videoId);
|
||||
@ -325,6 +378,8 @@ export default {
|
||||
this.getPlaylistData();
|
||||
this.getSponsors();
|
||||
if (!this.isEmbed && this.showComments) this.getComments();
|
||||
if (this.isEmbed) document.querySelector("html").style.overflow = "hidden";
|
||||
window.addEventListener("click", this.handleClick);
|
||||
window.addEventListener("resize", () => {
|
||||
this.smallView = this.smallViewQuery.matches;
|
||||
});
|
||||
@ -336,7 +391,7 @@ export default {
|
||||
this.showDesc = !this.getPreferenceBoolean("minimizeDescription", false);
|
||||
this.showRecs = !this.getPreferenceBoolean("minimizeRecommendations", false);
|
||||
this.showChapters = !this.getPreferenceBoolean("minimizeChapters", false);
|
||||
if (this.video.duration) {
|
||||
if (this.video?.duration) {
|
||||
document.title = this.video.title + " - Piped";
|
||||
this.$refs.videoPlayer.loadVideo();
|
||||
}
|
||||
@ -345,24 +400,45 @@ export default {
|
||||
deactivated() {
|
||||
this.active = false;
|
||||
window.removeEventListener("scroll", this.handleScroll);
|
||||
this.dismiss();
|
||||
},
|
||||
unmounted() {
|
||||
window.removeEventListener("scroll", this.handleScroll);
|
||||
window.removeEventListener("click", this.handleClick);
|
||||
this.dismiss();
|
||||
},
|
||||
methods: {
|
||||
fetchVideo() {
|
||||
return this.fetchJson(this.apiUrl() + "/streams/" + this.getVideoId());
|
||||
},
|
||||
async fetchSponsors() {
|
||||
return await this.fetchJson(this.apiUrl() + "/sponsors/" + this.getVideoId(), {
|
||||
category:
|
||||
'["' +
|
||||
this.getPreferenceString("selectedSkip", "sponsor,interaction,selfpromo,music_offtopic").replaceAll(
|
||||
",",
|
||||
'","',
|
||||
) +
|
||||
'"]',
|
||||
var selectedSkip = this.getPreferenceString(
|
||||
"selectedSkip",
|
||||
"sponsor,interaction,selfpromo,music_offtopic",
|
||||
).split(",");
|
||||
const skipOptions = this.getPreferenceJSON("skipOptions");
|
||||
if (skipOptions !== undefined) {
|
||||
selectedSkip = Object.keys(skipOptions).filter(
|
||||
k => skipOptions[k] !== undefined && skipOptions[k] !== "no",
|
||||
);
|
||||
}
|
||||
|
||||
const sponsors = await this.fetchJson(this.apiUrl() + "/sponsors/" + this.getVideoId(), {
|
||||
category: JSON.stringify(selectedSkip),
|
||||
});
|
||||
|
||||
sponsors?.segments?.forEach(segment => {
|
||||
const option = skipOptions[segment.category];
|
||||
segment.autoskip = option === undefined || option === "auto";
|
||||
});
|
||||
|
||||
const minSegmentLength = Math.max(this.getPreferenceNumber("minSegmentLength", 0), 0);
|
||||
sponsors.segments = sponsors.segments?.filter(segment => {
|
||||
const length = segment.segment[1] - segment.segment[0];
|
||||
return length >= minSegmentLength;
|
||||
});
|
||||
|
||||
return sponsors;
|
||||
},
|
||||
toggleComments() {
|
||||
this.showComments = !this.showComments;
|
||||
@ -395,13 +471,10 @@ export default {
|
||||
elem.outerHTML = elem.getAttribute("href");
|
||||
});
|
||||
xmlDoc.querySelectorAll("br").forEach(elem => (elem.outerHTML = "\n"));
|
||||
this.video.description = this.urlify(xmlDoc.querySelector("body").innerHTML)
|
||||
.replaceAll(/(?:http(?:s)?:\/\/)?(?:www\.)?youtube\.com(\/[/a-zA-Z0-9_?=&-]*)/gm, "$1")
|
||||
.replaceAll(
|
||||
/(?:http(?:s)?:\/\/)?(?:www\.)?youtu\.be\/(?:watch\?v=)?([/a-zA-Z0-9_?=&-]*)/gm,
|
||||
"/watch?v=$1",
|
||||
)
|
||||
.replaceAll("\n", "<br>");
|
||||
this.video.description = rewriteDescription(xmlDoc.querySelector("body").innerHTML);
|
||||
this.updateWatched(this.video.relatedStreams);
|
||||
|
||||
this.fetchDeArrowContent(this.video.relatedStreams);
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -422,6 +495,9 @@ export default {
|
||||
}
|
||||
}
|
||||
});
|
||||
await this.fetchPlaylistPages().then(() => {
|
||||
this.fetchDeArrowContent(this.playlist.relatedStreams);
|
||||
});
|
||||
}
|
||||
},
|
||||
async fetchPlaylistPages() {
|
||||
@ -500,6 +576,35 @@ export default {
|
||||
}
|
||||
this.subscribed = !this.subscribed;
|
||||
},
|
||||
handleClick(event) {
|
||||
if (!event || !event.target) return;
|
||||
if (!event.target.matches("a[href]")) return;
|
||||
const target = event.target;
|
||||
if (!target.getAttribute("href")) return;
|
||||
if (this.handleTimestampLinks(target)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
handleTimestampLinks(target) {
|
||||
try {
|
||||
const url = new URL(target.getAttribute("href"), document.baseURI);
|
||||
if (
|
||||
url.searchParams.size > 2 ||
|
||||
url.searchParams.get("v") !== this.getVideoId() ||
|
||||
!url.searchParams.has("t")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const time = parseTimeParam(url.searchParams.get("t"));
|
||||
if (time) {
|
||||
this.navigate(time);
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
handleScroll() {
|
||||
if (this.loading || !this.comments || !this.comments.nextpage) return;
|
||||
if (window.innerHeight + window.scrollY >= this.$refs.comments?.offsetHeight - window.innerHeight) {
|
||||
@ -523,6 +628,98 @@ export default {
|
||||
onTimeUpdate(time) {
|
||||
this.currentTime = time;
|
||||
},
|
||||
onVideoEnded() {
|
||||
if (
|
||||
!this.selectedAutoLoop &&
|
||||
this.selectedAutoPlay &&
|
||||
(this.playlist?.relatedStreams?.length > 0 || this.video.relatedStreams.length > 0)
|
||||
) {
|
||||
this.showToast();
|
||||
}
|
||||
},
|
||||
showToast() {
|
||||
this.counter = this.defaultCounter;
|
||||
if (this.counter < 1) {
|
||||
this.navigateNext();
|
||||
return;
|
||||
}
|
||||
if (this.timeoutCounter) clearInterval(this.timeoutCounter);
|
||||
this.timeoutCounter = setInterval(() => {
|
||||
this.counter--;
|
||||
if (this.counter === 0) {
|
||||
this.dismiss();
|
||||
this.navigateNext();
|
||||
}
|
||||
}, 1000);
|
||||
this.shouldShowToast = true;
|
||||
},
|
||||
dismiss() {
|
||||
clearInterval(this.timeoutCounter);
|
||||
this.shouldShowToast = false;
|
||||
},
|
||||
navigateNext() {
|
||||
const params = this.$route.query;
|
||||
let url = this.playlist?.relatedStreams?.[this.index]?.url ?? this.video.relatedStreams[0].url;
|
||||
const searchParams = new URLSearchParams();
|
||||
for (var param in params)
|
||||
switch (param) {
|
||||
case "v":
|
||||
case "t":
|
||||
break;
|
||||
case "index":
|
||||
if (this.index < this.playlist.relatedStreams.length) searchParams.set("index", this.index + 1);
|
||||
break;
|
||||
case "list":
|
||||
if (this.index < this.playlist.relatedStreams.length) searchParams.set("list", params.list);
|
||||
break;
|
||||
default:
|
||||
searchParams.set(param, params[param]);
|
||||
break;
|
||||
}
|
||||
// save the fullscreen state
|
||||
searchParams.set("fullscreen", this.$refs.videoPlayer.$ui.getControls().isFullScreenEnabled());
|
||||
const paramStr = searchParams.toString();
|
||||
if (paramStr.length > 0) url += "&" + paramStr;
|
||||
this.$router.push(url);
|
||||
},
|
||||
downloadCurrentFrame() {
|
||||
const video = document.querySelector("video");
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
|
||||
const context = canvas.getContext("2d");
|
||||
context.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
|
||||
let link = document.createElement("a");
|
||||
const currentTime = Math.round(video.currentTime * 1000) / 1000;
|
||||
link.download = `${this.video.title}_${currentTime}s.png`;
|
||||
link.href = canvas.toDataURL();
|
||||
link.click();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.v-enter-from,
|
||||
.v-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(100%) scale(0.5);
|
||||
}
|
||||
.description a {
|
||||
text-decoration: underline;
|
||||
filter: brightness(0.75);
|
||||
}
|
||||
@media (width <= 768px) {
|
||||
.share-btn {
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
.share-btn strong {
|
||||
display: none;
|
||||
}
|
||||
.share-btn svg {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
1
src/locales/ang.json
Normal file
1
src/locales/ang.json
Normal file
@ -0,0 +1 @@
|
||||
{}
|
@ -4,18 +4,22 @@
|
||||
"login": "تسجيل الدخول",
|
||||
"register": "إنشاء حساب",
|
||||
"preferences": "الإعدادات",
|
||||
"history": "تاريخ التصفح",
|
||||
"history": "سجل المشاهدة",
|
||||
"subscriptions": "الاشتراكات",
|
||||
"playlists": "قوائم التشغيل",
|
||||
"feed": "التغذية",
|
||||
"feed": "محتوى الاشتراكات",
|
||||
"account": "الحساب",
|
||||
"instance": "الخادم",
|
||||
"player": "المشغل",
|
||||
"livestreams": "البث المباشر",
|
||||
"channels": "القنوات"
|
||||
"channels": "القنوات",
|
||||
"bookmarks": "الاشارات المرجعيه",
|
||||
"channel_groups": "مجموعات القنوات",
|
||||
"dearrow": "دي ارو"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "شاهد عبر"
|
||||
"watch_on": "شاهد عبر",
|
||||
"failed": "فشل مع رمز الخطأ {0}، راجع السجلات لمزيد من المعلومات"
|
||||
},
|
||||
"actions": {
|
||||
"subscribe": "اشتراك - {count}",
|
||||
@ -41,7 +45,7 @@
|
||||
"enable_sponsorblock": "تفعيل مانع الإعلانات",
|
||||
"auto": "تلقائي",
|
||||
"dark": "داكن",
|
||||
"search": "بحث",
|
||||
"search": "بحث (Ctrl+K)",
|
||||
"autoplay_video": "تشغيل تلقائي",
|
||||
"audio_only": "صوت فقط",
|
||||
"default_quality": "الجودة الأساسية",
|
||||
@ -50,7 +54,7 @@
|
||||
"skip_interaction": "تخطي تذكير التفاعل (اشتراك)",
|
||||
"skip_non_music": "تخطي الموسيقى: قسم غير الموسيقى",
|
||||
"theme": "السمة",
|
||||
"instance_selection": "تحديد المثيل",
|
||||
"instance_selection": "قائمة الخوادم",
|
||||
"export_to_json": "تصدير إلى JSON",
|
||||
"show_more": "اظهار المزيد",
|
||||
"skip_outro": "تخطي بطاقات النهاية / الاعتمادات",
|
||||
@ -60,15 +64,15 @@
|
||||
"skip_filler_tangent": "تخطي المحتوى الغير مهم",
|
||||
"show_markers": "إظهار العلامات على المشغل",
|
||||
"buffering_goal": "هدف التخزين المؤقت (بالثواني)",
|
||||
"country_selection": "اختيار البلد",
|
||||
"country_selection": "البلد",
|
||||
"default_homepage": "الصفحة الرئيسية الافتراضية",
|
||||
"show_comments": "إظهار التعليقات",
|
||||
"minimize_description_default": "تصغير الوصف بشكل افتراضي",
|
||||
"store_watch_history": "تخزين سجل المشاهدة",
|
||||
"language_selection": "اختيار اللغة",
|
||||
"language_selection": "اللغة",
|
||||
"instances_list": "قائمة المثيلات",
|
||||
"enabled_codecs": "برامج الترميز الممكنة (متعددة)",
|
||||
"import_from_json": "استيراد من JSON/CSV",
|
||||
"import_from_json": "استيراد من JSON",
|
||||
"loop_this_video": "تكرار هذا الفيديو",
|
||||
"auto_play_next_video": "التشغيل التلقائي للفيديو التالي",
|
||||
"donations": "التبرعات للتطوير",
|
||||
@ -90,7 +94,7 @@
|
||||
"minimize_recommendations_default": "تقليل التوصيات بشكل افتراضي",
|
||||
"invalidate_session": "تسجيل الخروج من جميع الأجهزة",
|
||||
"different_auth_instance": "استخدام مثيل مختلف للمصادقة",
|
||||
"instance_auth_selection": "تحديد مثيل Autentication",
|
||||
"instance_auth_selection": "خادم المصادقة",
|
||||
"clone_playlist": "استنساخ قائمة التشغيل",
|
||||
"clone_playlist_success": "تم استنساخها بنجاح!",
|
||||
"download_as_txt": "تنزيل بتنسيق .txt",
|
||||
@ -105,10 +109,8 @@
|
||||
"follow_link": "اتبع الرابط",
|
||||
"copy_link": "نسخ الرابط",
|
||||
"time_code": "رمز الوقت (بالثواني)",
|
||||
"rename_playlist": "إعادة تسمية قائمة التشغيل",
|
||||
"new_playlist_name": "اسم قائمة تشغيل جديد",
|
||||
"show_chapters": "الفصول",
|
||||
"store_search_history": "حفظ سجل البحث",
|
||||
"store_search_history": "تخزين سجل البحث",
|
||||
"documentation": "التوثيق",
|
||||
"status_page": "الحالة",
|
||||
"source_code": "شفرة المصدر",
|
||||
@ -120,7 +122,31 @@
|
||||
"show_watch_on_youtube": "عرض زر مشاهدة على يوتيوب",
|
||||
"minimize_chapters_default": "تصغير الفصول بشكل افتراضي",
|
||||
"no_valid_playlists": "لا يحتوي الملف على قوائم تشغيل صالحة!",
|
||||
"with_playlist": "المشاركة مع قائمة التشغيل"
|
||||
"with_playlist": "المشاركة مع قائمة التشغيل",
|
||||
"bookmark_playlist": "الاشاره المرجعيه",
|
||||
"playlist_bookmarked": "تم وضعها في الاشارات المرجعية",
|
||||
"skip_button_only": "إظهار زر التخطي",
|
||||
"skip_automatically": "تلقائيا",
|
||||
"min_segment_length": "الحد الأدنى لطول الفصل (بالثواني)",
|
||||
"skip_segment": "تخطي الجزء",
|
||||
"show_less": "عرض أقل",
|
||||
"autoplay_next_countdown": "العد التنازلي الافتراضي حتى الفيديو التالي ( ثانية )",
|
||||
"dismiss": "تجاهل",
|
||||
"group_name": "أسم المجموعة",
|
||||
"create_group": "إنشاء مجموعة",
|
||||
"auto_display_captions": "عرض التسميات التوضيحية تلقائيا",
|
||||
"cancel": "إلغاء",
|
||||
"okay": "حسنًا",
|
||||
"playlist_description": "وصف قائمة التشغيل",
|
||||
"playlist_name": "اسم قائمة التشغيل",
|
||||
"edit_playlist": "تعديل قائمة التشغيل",
|
||||
"show_search_suggestions": "إظهار اقتراحات البحث",
|
||||
"chapters_layout_mobile": "تخطيط الفصول على الهاتف",
|
||||
"delete_automatically": "الحذف تلقائيا بعد",
|
||||
"enable_dearrow": "تمكين دي ارو",
|
||||
"generate_qrcode": "إنشاء رمز الاستجابة السريعة",
|
||||
"import_from_json_csv": "استيراد من JSON/CSV",
|
||||
"download_frame": "إطار التحميل"
|
||||
},
|
||||
"video": {
|
||||
"sponsor_segments": "المقاطع الإعلانية",
|
||||
@ -130,7 +156,13 @@
|
||||
"views": "{views} عدد المشاهدات",
|
||||
"shorts": "فديوهات قصيرة",
|
||||
"videos": "الفيديوات",
|
||||
"live": "{0} مباشر"
|
||||
"live": "{0} مباشر",
|
||||
"all": "الكل",
|
||||
"category": "الفئة",
|
||||
"chapters_vertical": "رَأسِيّ",
|
||||
"chapters_horizontal": "أفقي",
|
||||
"visibility": "الظهور",
|
||||
"license": "الترخيص"
|
||||
},
|
||||
"search": {
|
||||
"channels": "يوتيوب: القنوات",
|
||||
@ -141,7 +173,8 @@
|
||||
"music_videos": "YT Music: مقاطع فيديو",
|
||||
"did_you_mean": "هل تقصد: {0}؟",
|
||||
"music_playlists": "YT Music: قوائم التشغيل",
|
||||
"music_albums": "YT Music: ألبومات"
|
||||
"music_albums": "YT Music: ألبومات",
|
||||
"music_artists": "YT الموسيقى: الفنانين"
|
||||
},
|
||||
"preferences": {
|
||||
"version": "الإصدار",
|
||||
@ -160,7 +193,9 @@
|
||||
},
|
||||
"login": {
|
||||
"username": "اسم المستخدم",
|
||||
"password": "كلمة السر"
|
||||
"password": "كلمة السر",
|
||||
"passwords_incorrect": "كلمة المرور لم تتطابق!",
|
||||
"password_confirm": "تأكيد كلمة المرور"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "مشترك في: {0}"
|
||||
@ -173,6 +208,12 @@
|
||||
"page_not_found": "لم يتم العثور على الصفحة",
|
||||
"copied": "نسخ!",
|
||||
"cannot_copy": "لا يمكن نسخه!",
|
||||
"local_storage": "يتطلب هذا الإجراء التخزين المحلي، هل يتم تمكين ملفات تعريف الارتباط؟"
|
||||
"local_storage": "يتطلب هذا الإجراء التخزين المحلي، هل يتم تمكين ملفات تعريف الارتباط؟",
|
||||
"register_no_email_note": "لا ينصح باستخدام البريد الإلكتروني كاسم مستخدم. المضي قدما على أي حال؟",
|
||||
"next_video_countdown": "تشغيل الفيديو التالي بعد { 0 } ق",
|
||||
"weeks": "{amount} أسبوع (أسابيع)",
|
||||
"hours": "{amount} ساعة (ساعات)",
|
||||
"months": "{amount} شهر (أشهر)",
|
||||
"days": "{amount} يوم (أيام)"
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,18 @@
|
||||
"login": "Daxil ol",
|
||||
"register": "Qeydiyyatdan keç",
|
||||
"feed": "Axın",
|
||||
"preferences": "Seçimlər",
|
||||
"preferences": "Üstünlüklər",
|
||||
"history": "Tarixçə",
|
||||
"subscriptions": "Abunəliklər",
|
||||
"playlists": "Pleylistlər",
|
||||
"playlists": "Oynatma Siyahıları",
|
||||
"account": "Hesab",
|
||||
"instance": "Nümunə",
|
||||
"player": "Oynadıcı",
|
||||
"livestreams": "Canlı yayımlar",
|
||||
"channels": "Kanallar"
|
||||
"livestreams": "Canlı Yayımlar",
|
||||
"channels": "Kanallar",
|
||||
"bookmarks": "Əlfəcinlər",
|
||||
"channel_groups": "Kanal qrupları",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "{0} saytında bax"
|
||||
@ -30,12 +33,12 @@
|
||||
"uses_api_from": "API-dən istifadə edir ",
|
||||
"enable_sponsorblock": "SponsorBlok'u Aktivləşdir",
|
||||
"skip_sponsors": "Sponsorları Ötür",
|
||||
"skip_intro": "Fasilə/Giriş Animasiyasını Ötür",
|
||||
"skip_outro": "Bitiş Kartları/Kreditləri Ötür",
|
||||
"skip_intro": "Fasilə/Giriş Animasiyasın Ötür",
|
||||
"skip_outro": "Son Kartları/Kreditləri Ötür",
|
||||
"skip_preview": "Önbaxışı/Anonsu Ötür",
|
||||
"skip_interaction": "İnteraksiya Xatırladıcısını Ötür(Abunə Ol)",
|
||||
"skip_self_promo": "Ödənişsiz/Özünü Reklamı Ötür",
|
||||
"skip_non_music": "Musiqini Ötür: Musiqi Olmayan Bölmə",
|
||||
"skip_interaction": "Əlaqələndirmə Xatırladıcısın Ötür(Abunə Ol)",
|
||||
"skip_self_promo": "Ödənilməmiş/Özünü Reklamı Ötür",
|
||||
"skip_non_music": "Musiqini Ötür: Musiqisiz Bölmə",
|
||||
"skip_highlight": "Anonsu Ötür",
|
||||
"skip_filler_tangent": "Doldurucu Səhnələri Ötür",
|
||||
"theme": "Tema",
|
||||
@ -44,70 +47,68 @@
|
||||
"light": "İşıqlı",
|
||||
"autoplay_video": "Videonu Avto-oynat",
|
||||
"audio_only": "Yalnız Səs",
|
||||
"default_quality": "Defolt Keyfiyyət",
|
||||
"default_quality": "Standart Keyfiyyət",
|
||||
"buffering_goal": "Tamponlama hədəfi (saniyələrlə)",
|
||||
"export_to_json": "JSON-a İxrac Et",
|
||||
"import_from_json": "JSON/CSV-dan İdxal Et",
|
||||
"import_from_json": "JSON -dan İdxal Et",
|
||||
"loop_this_video": "Bu Videonu Təkrarla",
|
||||
"auto_play_next_video": "Növbəti Videonu Avto-Oynat",
|
||||
"donations": "İnkişaf ianələri",
|
||||
"minimize_description": "Açıqlamanı Kiçilt",
|
||||
"show_description": "Açıqlamanı Göstər",
|
||||
"minimize_recommendations": "Tövsiyələri kiçilt",
|
||||
"minimize_recommendations": "Tövsiyələri Kiçilt",
|
||||
"show_recommendations": "Tövsiyələri Göstər",
|
||||
"disable_lbry": "Yayım üçün LBRY-ni deaktiv et",
|
||||
"enable_lbry_proxy": "LBRY üçün Proksi-ni Aktivləşdir",
|
||||
"view_ssl_score": "SSL Nəticəsinə Bax",
|
||||
"search": "Axtarış",
|
||||
"search": "Axtarış (Ctrl+K)",
|
||||
"filter": "Filtr",
|
||||
"loading": "Yüklənir...",
|
||||
"clear_history": "Tarixçəni Təmizlə",
|
||||
"hide_replies": "Cavabları Gizlət",
|
||||
"load_more_replies": "Daha Çox Cavab Yüklə",
|
||||
"add_to_playlist": "Pleylistə Əlavə Et",
|
||||
"remove_from_playlist": "Pleylistdən Sil",
|
||||
"delete_playlist_video_confirm": "Video pleylistdən silinsin?",
|
||||
"create_playlist": "Pleylist Yarat",
|
||||
"delete_playlist": "Pleylisti Sil",
|
||||
"select_playlist": "Pleylist Seç",
|
||||
"delete_playlist_confirm": "Bu pleylist silinsin?",
|
||||
"please_select_playlist": "Lütfən, pleylist seç",
|
||||
"country_selection": "Ölkə Seçimi",
|
||||
"default_homepage": "Defolt Əsas Səhifə",
|
||||
"add_to_playlist": "Oynatma siyahısına əlavə et",
|
||||
"remove_from_playlist": "Oynatma siyahısından təmizlə",
|
||||
"delete_playlist_video_confirm": "Video oynatma siyahısından silinsin?",
|
||||
"create_playlist": "Oynatma Siyahısı Yarat",
|
||||
"delete_playlist": "Oynatma Siyahısın Sil",
|
||||
"select_playlist": "Oynatma Siyahısı Seç",
|
||||
"delete_playlist_confirm": "Bu oynatma siyahısı silinsin?",
|
||||
"please_select_playlist": "Xahiş edilir, oynatma siyahısı seç",
|
||||
"country_selection": "Ölkə",
|
||||
"default_homepage": "Standart Əsas Səhifə",
|
||||
"show_comments": "Şərhləri Göstər",
|
||||
"instance_selection": "Nümunə Seçimi",
|
||||
"minimize_description_default": "Açıqlamanı Defolt Olaraq Kiçilt",
|
||||
"language_selection": "Dil Seçimi",
|
||||
"instance_selection": "İnstansiya",
|
||||
"minimize_description_default": "Açıqlamanı Standart Olaraq Kiçilt",
|
||||
"language_selection": "Dil",
|
||||
"instances_list": "Nümunələr Siyahısı",
|
||||
"show_more": "Daha Çox Göstər",
|
||||
"no": "Xeyr",
|
||||
"store_watch_history": "Baxış Tarixçəsini Saxla",
|
||||
"enabled_codecs": "Aktiv Kodeklər (Birdən çox)",
|
||||
"store_watch_history": "Baxış Tarixçəsin Saxla",
|
||||
"enabled_codecs": "Aktiv Kodlayıcılar (Çoxlu)",
|
||||
"yes": "Bəli",
|
||||
"show_markers": "Oynadıcıda Markerləri Göstər",
|
||||
"delete_account": "Hesabı Sil",
|
||||
"logout": "Bu cihazdan çıx",
|
||||
"minimize_recommendations_default": "Defolt olaraq Tövsiyələri kiçilt",
|
||||
"minimize_recommendations_default": "Standart olaraq Tövsiyələri kiçilt",
|
||||
"download_as_txt": ".txt kimi endir",
|
||||
"reset_preferences": "Seçimləri sıfırla",
|
||||
"reset_preferences": "Üstünlükləri sıfırla",
|
||||
"confirm_reset_preferences": "Seçimlərinizi sıfırlamaq istədiyinizə əminsiniz?",
|
||||
"backup_preferences": "Yedəkləmə seçimləri",
|
||||
"backup_preferences": "Nüsxələmə seçimləri",
|
||||
"restore_preferences": "Seçimləri bərpa et",
|
||||
"invalidate_session": "Bütün cihazlardan çıxın",
|
||||
"different_auth_instance": "Təsdiqləmə üçün fərqli nümunə istifadə et",
|
||||
"instance_auth_selection": "Təsdiqləmə Nümunəsi Seçimi",
|
||||
"clone_playlist": "Pleylisti Klonla",
|
||||
"instance_auth_selection": "Təsdiqləmə İnstansiyası",
|
||||
"clone_playlist": "Oynatma Siyahısın Klonla",
|
||||
"clone_playlist_success": "Uğurla klonlandı!",
|
||||
"rename_playlist": "Pleylist adını dəyiş",
|
||||
"time_code": "Vaxt kodu (saniyələrlə)",
|
||||
"store_search_history": "Axtarış tarixçəsini saxla",
|
||||
"documentation": "Sertifikatlaşdırma",
|
||||
"store_search_history": "Axtarış Tarixçəsin Saxla",
|
||||
"documentation": "Sənədləşdirmə",
|
||||
"status_page": "Vəziyyət",
|
||||
"source_code": "Mənbə kodu",
|
||||
"instance_donations": "Nümunə ianələri",
|
||||
"hide_watched": "Axında baxılan videoları gizlət",
|
||||
"show_chapters": "Bölmələr",
|
||||
"new_playlist_name": "Yeni pleylist adı",
|
||||
"share": "Paylaş",
|
||||
"with_timecode": "Vaxt kodu ilə paylaş",
|
||||
"follow_link": "Bağlantını izlə",
|
||||
@ -117,21 +118,45 @@
|
||||
"reply_count": "{count} cavab",
|
||||
"minimize_comments_default": "Şərhləri standart olaraq kiçilt",
|
||||
"minimize_comments": "Şərhləri Kiçilt",
|
||||
"minimize_chapters_default": "Defolt olaraq bölmələri kiçilt",
|
||||
"show_watch_on_youtube": "YouTube-da Baxış düyməsini göstər",
|
||||
"no_valid_playlists": "Faylda etibarlı pleylistlər yoxdur!",
|
||||
"with_playlist": "Pleylistlə paylaş"
|
||||
"minimize_chapters_default": "Standart olaraq bölmələri kiçilt",
|
||||
"show_watch_on_youtube": "YouTube-da Baxış düyməsin göstər",
|
||||
"no_valid_playlists": "Faylın etibarlı oynatma siyahıları yoxdur!",
|
||||
"with_playlist": "Oynatma siyahısıyla paylaş",
|
||||
"bookmark_playlist": "Əlfəcin",
|
||||
"playlist_bookmarked": "Əlfəcinləndi",
|
||||
"skip_button_only": "Ötürmə düyməsin göstər",
|
||||
"skip_automatically": "Avtomatik olaraq",
|
||||
"min_segment_length": "Minimum Seqment Uzunluğu (saniyələrlə)",
|
||||
"skip_segment": "Seqmenti ötür",
|
||||
"show_less": "Daha az göstər",
|
||||
"autoplay_next_countdown": "Növbəti videoya qədər standart geri sayım (saniyə)",
|
||||
"dismiss": "Rədd et",
|
||||
"create_group": "Qrup yarat",
|
||||
"group_name": "Qrup adı",
|
||||
"cancel": "Ləğv et",
|
||||
"edit_playlist": "Oynatma siyahısın redaktə et",
|
||||
"playlist_description": "Oynatma siyahısı təsviri",
|
||||
"okay": "Oldu",
|
||||
"chapters_layout_mobile": "Mobildə Bölmələrin Tərtibatı",
|
||||
"playlist_name": "Oynatma siyahısı adı",
|
||||
"show_search_suggestions": "Axtarış təkliflərin göstər",
|
||||
"auto_display_captions": "Titrləri Avtomatik Göstər",
|
||||
"import_from_json_csv": "JSON/CSV-dən idxal et",
|
||||
"delete_automatically": "Sonranı avtomatik silin",
|
||||
"download_frame": "Yükləmə çərçivəsi",
|
||||
"enable_dearrow": "DeArrow'u Aktivləşdir",
|
||||
"generate_qrcode": "QR Kodu Yarat"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Tərəfindən Sabitləndi {author}",
|
||||
"disabled": "Şərhlər yükləyici tərəfindən deaktiv edilib.",
|
||||
"loading": "Şərhlər yüklənir...",
|
||||
"user_disabled": "Şərhlər tənzimləmələrdə deaktiv edilib."
|
||||
"pinned_by": "{author} tərəfindən sabitlənib",
|
||||
"disabled": "Şərhlər yükləyici tərəfindən bağlanıb.",
|
||||
"loading": "Şərhlər yüklənilir...",
|
||||
"user_disabled": "Şərhlər tənzimləmələrdə qeyri-aktiv edilib."
|
||||
},
|
||||
"preferences": {
|
||||
"instance_name": "Nümunə Adı",
|
||||
"instance_locations": "Nümunə Məkanları",
|
||||
"has_cdn": "CDN varmı?",
|
||||
"has_cdn": "CDN Varmı?",
|
||||
"registered_users": "Qeydiyyatdan Keçmiş İstifadəçilər",
|
||||
"version": "Versiya",
|
||||
"up_to_date": "Güncəllənib?",
|
||||
@ -139,28 +164,37 @@
|
||||
},
|
||||
"login": {
|
||||
"username": "İstifadəçi Adı",
|
||||
"password": "Şifrə"
|
||||
"password": "Şifrə",
|
||||
"password_confirm": "Parolu təsdiqlə",
|
||||
"passwords_incorrect": "Parollar uyğunlaşmır!"
|
||||
},
|
||||
"video": {
|
||||
"videos": "Videolar",
|
||||
"views": "{views} baxış",
|
||||
"watched": "Baxılıb",
|
||||
"sponsor_segments": "Sponsorlar Seqmentləri",
|
||||
"ratings_disabled": "Reytinqlər Deaktivdir",
|
||||
"ratings_disabled": "Reytinqlər Qeyri-aktivdir",
|
||||
"chapters": "Bölmələr",
|
||||
"live": "{0} Canlı",
|
||||
"shorts": "Qısa"
|
||||
"shorts": "Qısa",
|
||||
"all": "Hamısı",
|
||||
"category": "Kateqoriya",
|
||||
"chapters_horizontal": "Üfüqi",
|
||||
"chapters_vertical": "Şaquli",
|
||||
"license": "Lisenziya",
|
||||
"visibility": "Görünüş"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Bunu nəzərdə tutursunuz: {0}?",
|
||||
"all": "YouTube: Hamısı",
|
||||
"videos": "YouTube: Videolar",
|
||||
"channels": "YouTube: Kanallar",
|
||||
"playlists": "YouTube: Pleylistlər",
|
||||
"playlists": "YouTube: Oynatma siyahıları",
|
||||
"music_songs": "YT Music: Mahnılar",
|
||||
"music_videos": "YT Music: Videolar",
|
||||
"music_albums": "YT Music: Albomlar",
|
||||
"music_playlists": "YT Music: Pleylistlər"
|
||||
"music_playlists": "YT Music: Oynatma Siyahıları",
|
||||
"music_artists": "YT Music: Sənətkarlar"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Abunə oldu: {0}"
|
||||
@ -169,10 +203,16 @@
|
||||
"preferences_note": "Qeyd: seçimlər brauzerinizin yerli yaddaşında saxlanılır. Brauzer məlumatlarınızın silinməsi onları sıfırlayacaq."
|
||||
},
|
||||
"info": {
|
||||
"preferences_note": "Qeyd: Seçimlər brauzerinizin yerli yaddaşında saxlanılır. Brauzer məlumatlarınızın silinməsi onları sıfırlayacaq.",
|
||||
"preferences_note": "Qeyd: Seçimlər brauzerinizin öz yaddaşında saxlanılır. Brauzer məlumatınızın silinməsi onları sıfırlayacaq.",
|
||||
"page_not_found": "Səhifə tapılmadı",
|
||||
"copied": "Kopyalandı!",
|
||||
"cannot_copy": "Kopyalanmır!",
|
||||
"local_storage": "Bu fəaliyyət localStorage tələb edir, məlumat bazası aktivdir?"
|
||||
"copied": "Nüsxələndi!",
|
||||
"cannot_copy": "Nüsxələnmir!",
|
||||
"local_storage": "Bu fəaliyyət yerli yaddaş tələb edir, məlumat bazası aktivdir?",
|
||||
"register_no_email_note": "E-poçt-u istifadəçi adı kimi istifadə etmək tövsiyə edilmir. Baxmayaraq ki, davam edilsin?",
|
||||
"next_video_countdown": "Növbəti video {0} saniyəyə oynadılır",
|
||||
"hours": "{amount} saat",
|
||||
"days": "{amount} gün",
|
||||
"months": "{amount} ay",
|
||||
"weeks": "{amount} həftə"
|
||||
}
|
||||
}
|
||||
|
169
src/locales/bg.json
Normal file
169
src/locales/bg.json
Normal file
@ -0,0 +1,169 @@
|
||||
{
|
||||
"titles": {
|
||||
"channels": "Канали",
|
||||
"login": "Вход",
|
||||
"register": "Регистрация",
|
||||
"feed": "Емисия",
|
||||
"history": "История",
|
||||
"playlists": "Плейлисти",
|
||||
"instance": "Инстанция",
|
||||
"player": "Плейър",
|
||||
"livestreams": "Излъчвания на живо",
|
||||
"bookmarks": "Отметки",
|
||||
"trending": "Набиращи популярност",
|
||||
"account": "Профил",
|
||||
"preferences": "Настройки",
|
||||
"subscriptions": "Абонаменти",
|
||||
"dearrow": "DeArrow",
|
||||
"channel_groups": "Канални групи"
|
||||
},
|
||||
"actions": {
|
||||
"most_recent": "Най-скорошен",
|
||||
"unsubscribe": "Отписване - {count}",
|
||||
"uses_api_from": "Използва API от ",
|
||||
"skip_sponsors": "Пропускане на спонсори",
|
||||
"skip_preview": "Пропускане на преглед/обобщение",
|
||||
"skip_self_promo": "Пропускане на самореклама/неплатена реклама",
|
||||
"min_segment_length": "Минимална дължина на сегмента (в секунди)",
|
||||
"default_quality": "Качество по подразбиране",
|
||||
"minimize_comments_default": "Минимизиране на коментарите по подразбиране",
|
||||
"subscribe": "Абониране - {count}",
|
||||
"view_subscriptions": "Преглед на абонаменти",
|
||||
"sort_by": "Сортиране по:",
|
||||
"least_recent": "Най-малко скорошен",
|
||||
"channel_name_asc": "Име на канал (А-Я)",
|
||||
"channel_name_desc": "Име на канал (Я-А)",
|
||||
"back": "Назад",
|
||||
"enable_sponsorblock": "Активиране на SponsorBlock",
|
||||
"skip_button_only": "Показване на бутона за пропускане",
|
||||
"skip_automatically": "Автоматично",
|
||||
"skip_intro": "Пропускане на прекъсване/въвеждаща анимация",
|
||||
"skip_outro": "Пропускане на крайни карти/надписи",
|
||||
"skip_interaction": "Пропускане на напомняне за абониране",
|
||||
"skip_non_music": "Попускане Немузикален раздел в музика",
|
||||
"skip_highlight": "Пропускане на видео акцент",
|
||||
"show_markers": "Показване на маркери в плейъра",
|
||||
"skip_segment": "Пропускане на сегмент",
|
||||
"theme": "Тема",
|
||||
"auto": "Автоматично",
|
||||
"dark": "Тъмна",
|
||||
"light": "Светла",
|
||||
"autoplay_video": "Автоматично пускане на видео",
|
||||
"audio_only": "Само аудио",
|
||||
"buffering_goal": "Буфериране (в секунди)",
|
||||
"country_selection": "Избор на държава",
|
||||
"default_homepage": "Начална страница по подразбиране",
|
||||
"minimize_description_default": "Минимизиране на описанието по подразбиране",
|
||||
"store_watch_history": "Запазване на историята на гледане",
|
||||
"language_selection": "Избор на език",
|
||||
"instances_list": "Списък на инстанциите",
|
||||
"enabled_codecs": "Разрешени кодеци (множество)",
|
||||
"instance_selection": "Избор на инстанция",
|
||||
"show_more": "Покажи повече",
|
||||
"yes": "Да",
|
||||
"no": "Не",
|
||||
"export_to_json": "Експорт в JSON",
|
||||
"import_from_json": "Импорт от JSON/CSV",
|
||||
"loop_this_video": "Повтаряне на това видео",
|
||||
"auto_play_next_video": "Автоматично пускане на следващото видео",
|
||||
"donations": "Дарения за разработка",
|
||||
"minimize_comments": "Минимизиране на коментарите",
|
||||
"show_comments": "Показване на коментарите",
|
||||
"show_description": "Показване на описание",
|
||||
"search": "Търси",
|
||||
"minimize_description": "Минимизиране на описание",
|
||||
"filter": "Филтър",
|
||||
"clear_history": "Изчистване на историята",
|
||||
"minimize_recommendations": "Минимизиране на препоръчани",
|
||||
"show_recommendations": "Показване на препоръчани",
|
||||
"view_ssl_score": "Преглед на SSL резултат",
|
||||
"loading": "Зареждане...",
|
||||
"hide_replies": "Скрий отговорите",
|
||||
"load_more_replies": "Зареди още отговори",
|
||||
"remove_from_playlist": "Премахване от плейлист",
|
||||
"create_playlist": "Създаване на плейлист",
|
||||
"reset_preferences": "Нулиране на настройките",
|
||||
"with_timecode": "Сподели с текущото време",
|
||||
"piped_link": "Piped връзка",
|
||||
"documentation": "Документация",
|
||||
"delete_account": "Изтрий акаунта",
|
||||
"download_as_txt": "Изтегляне като .txt",
|
||||
"share": "Сподели",
|
||||
"follow_link": "Последвай връзката",
|
||||
"add_to_playlist": "Добави към плейлист",
|
||||
"delete_playlist_video_confirm": "Да се премахне ли видеото от плейлиста?",
|
||||
"show_watch_on_youtube": "Показване на бутона \"Гледай в YouTube\"",
|
||||
"source_code": "Изходен код",
|
||||
"minimize_chapters_default": "Минимизиране на разделите по подразбиране",
|
||||
"minimize_recommendations_default": "Минимизиране на препоръчани по подразбиране",
|
||||
"show_chapters": "Раздели",
|
||||
"logout": "Отписване от това устройство",
|
||||
"clone_playlist": "Клониране на плейлист",
|
||||
"clone_playlist_success": "Успешно клониране!",
|
||||
"backup_preferences": "Архивиране на настройките",
|
||||
"back_to_home": "Обратно към начална страница",
|
||||
"status_page": "Статус",
|
||||
"copy_link": "Копирай връзката",
|
||||
"time_code": "Текущо време (в секунди)",
|
||||
"reply_count": "{count} отговора",
|
||||
"restore_preferences": "Възстановяване на настройките",
|
||||
"invalidate_session": "Отписване от всички устройства",
|
||||
"different_auth_instance": "Използване на различна инстанция за удостоверяване",
|
||||
"store_search_history": "Запазване на историята на търсене",
|
||||
"instance_auth_selection": "Избор на инстанция за удостоверяване",
|
||||
"confirm_reset_preferences": "Сигурни ли сте, че искате да нулирате настройките?",
|
||||
"hide_watched": "Скриване на гледани видеоклипове в Абонаменти",
|
||||
"enable_dearrow": "Включи DeArrow"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Гледай в {0}"
|
||||
},
|
||||
"login": {
|
||||
"username": "Потребителско име",
|
||||
"password": "Парола"
|
||||
},
|
||||
"video": {
|
||||
"videos": "Видеоклипове",
|
||||
"views": "{views} показвания",
|
||||
"chapters": "Раздели",
|
||||
"all": "Всички",
|
||||
"watched": "Гледани",
|
||||
"category": "Категория"
|
||||
},
|
||||
"preferences": {
|
||||
"version": "Версия",
|
||||
"registered_users": "Регистрирани потребители",
|
||||
"instance_locations": "Местоположения на инстанция",
|
||||
"instance_name": "Име на инстанция",
|
||||
"has_cdn": "Има ли CDN?",
|
||||
"up_to_date": "Актуален?",
|
||||
"ssl_score": "SSL резултат"
|
||||
},
|
||||
"comment": {
|
||||
"disabled": "Коментарите са деактивирани.",
|
||||
"pinned_by": "Фиксиран от {author}",
|
||||
"loading": "Коментарите се зареждат...",
|
||||
"user_disabled": "Коментарите са деактивирани в настройките."
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Имахте предвид: {0}?",
|
||||
"all": "YouTube: Всички",
|
||||
"videos": "YouTube: Видеоклипове",
|
||||
"channels": "YouTube: Канали",
|
||||
"playlists": "YouTube: Плейлисти",
|
||||
"music_songs": "YT Music: Песни",
|
||||
"music_videos": "YT Music: Видеоклипове",
|
||||
"music_albums": "YT Music: Албуми",
|
||||
"music_playlists": "YT Music: Плейлисти"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Абониран за: {0}"
|
||||
},
|
||||
"info": {
|
||||
"page_not_found": "Страницата не е намерена",
|
||||
"copied": "Копирано!",
|
||||
"cannot_copy": "Не може да се копира!",
|
||||
"local_storage": "Това действие изисква localStorage, разрешени ли са бисквитките?",
|
||||
"register_no_email_note": "Използването на имейл като потребителско име не се препоръчва. Продължете все пак?"
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@
|
||||
"audio_only": "Samo zvuk",
|
||||
"default_homepage": "Zadana početna stranica",
|
||||
"loop_this_video": "Stavite ovaj video na ponavljanje",
|
||||
"search": "Pretraga",
|
||||
"search": "Pretraga (Ctrl+K)",
|
||||
"skip_preview": "Preskočite pregled",
|
||||
"skip_non_music": "Preskočite muziku: sekcija bez muzike",
|
||||
"skip_self_promo": "Preskočite neplaćenu/samo-promociju",
|
||||
@ -77,8 +77,6 @@
|
||||
"minimize_chapters_default": "Smanjite poglavlja po zadanom",
|
||||
"show_watch_on_youtube": "Prikaži „Gledaj na YouTube-u” dugme",
|
||||
"different_auth_instance": "Koristite drugu instancu za autentifikaciju",
|
||||
"rename_playlist": "Preimenuj listu izvođenja",
|
||||
"new_playlist_name": "Novi naziv liste izvođenja",
|
||||
"with_timecode": "Podijelite s vremenskim kodom",
|
||||
"piped_link": "Piped poveznica",
|
||||
"follow_link": "Prati poveznicu",
|
||||
@ -102,7 +100,16 @@
|
||||
"minimize_comments": "Minimizirajte komentare",
|
||||
"delete_account": "Izbriši račun",
|
||||
"minimize_recommendations_default": "Smanjite preporuke po zadanom",
|
||||
"reset_preferences": "Vrati postavke na zadano"
|
||||
"reset_preferences": "Vrati postavke na zadano",
|
||||
"bookmark_playlist": "Bilježak",
|
||||
"playlist_bookmarked": "Obilježeno",
|
||||
"show_less": "Prikaži manje",
|
||||
"skip_button_only": "Prikaži dugme za preskakanje",
|
||||
"skip_automatically": "Automatski",
|
||||
"min_segment_length": "Najmanja dužina segmenta (u sekundama)",
|
||||
"skip_segment": "Preskoči segment",
|
||||
"autoplay_next_countdown": "Zadano odbrojavanje do sljedećeg videa (u sekundama)",
|
||||
"dismiss": "Odbaci"
|
||||
},
|
||||
"titles": {
|
||||
"register": "Registrirajte se",
|
||||
@ -117,7 +124,8 @@
|
||||
"account": "Račun",
|
||||
"player": "Pokretnik",
|
||||
"channels": "Kanali",
|
||||
"livestreams": "Prijenosi uživo"
|
||||
"livestreams": "Prijenosi uživo",
|
||||
"bookmarks": "Bilješci"
|
||||
},
|
||||
"search": {
|
||||
"music_songs": "YT Music: Pjesme",
|
||||
@ -154,7 +162,9 @@
|
||||
"watched": "Pogledano",
|
||||
"videos": "Video zapisi",
|
||||
"live": "{0} Uživo",
|
||||
"shorts": "Kratki videi"
|
||||
"shorts": "Kratki videi",
|
||||
"category": "Kategorija",
|
||||
"all": "Sve"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Prikačeno od {author}",
|
||||
@ -170,6 +180,8 @@
|
||||
"cannot_copy": "Nije moguće kopirati!",
|
||||
"page_not_found": "Stranica nije pronađena",
|
||||
"copied": "Kopirano!",
|
||||
"local_storage": "Ova radnja zahtijeva lokalno pohranjivanje, jesu li kolačići omogućeni?"
|
||||
"local_storage": "Ova radnja zahtijeva lokalno pohranjivanje, jesu li kolačići omogućeni?",
|
||||
"register_no_email_note": "Korištenje e-maila kao korisničko ime se ne preporučuje. Svejedno nastaviti?",
|
||||
"next_video_countdown": "Reproduciranje sljedećeg videa u {0}"
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,8 @@
|
||||
"instance": "Instància",
|
||||
"player": "Reproductor",
|
||||
"livestreams": "Retransmissió en directe",
|
||||
"channels": "Canals"
|
||||
"channels": "Canals",
|
||||
"bookmarks": "Marcadors"
|
||||
},
|
||||
"actions": {
|
||||
"channel_name_desc": "Nom del Canal (Z-A)",
|
||||
@ -42,7 +43,7 @@
|
||||
"enabled_codecs": "Còdecs Habilitats (Múltiple)",
|
||||
"instances_list": "Llista d'Instàncies",
|
||||
"instance_selection": "Selecció d'Instàncies",
|
||||
"show_more": "Mostrar Més",
|
||||
"show_more": "Mostrar més",
|
||||
"yes": "Sí",
|
||||
"no": "No",
|
||||
"export_to_json": "Exportar a JSON",
|
||||
@ -102,8 +103,6 @@
|
||||
"time_code": "Moment (en segons)",
|
||||
"copy_link": "Copiar l'enllaç",
|
||||
"follow_link": "Vés a l'enllaç",
|
||||
"rename_playlist": "Canviar el nom de la llista de reproducció",
|
||||
"new_playlist_name": "Nom nou de la llista de reproducció",
|
||||
"store_search_history": "Emmagatzema l'historial de cerca",
|
||||
"instance_donations": "Donacions a instàncies",
|
||||
"hide_watched": "Amaga els vídeos vistos de Continguts",
|
||||
@ -114,7 +113,17 @@
|
||||
"show_watch_on_youtube": "Mostra el botó \"Veure a Youtube\"",
|
||||
"reply_count": "{count} respostes",
|
||||
"minimize_comments_default": "Minimitzar els comentaris per defecte",
|
||||
"minimize_comments": "Minimitza els comentaris"
|
||||
"minimize_comments": "Minimitza els comentaris",
|
||||
"no_valid_playlists": "L'arxiu no conté llistes de reproducció vàlides!",
|
||||
"bookmark_playlist": "Marcador",
|
||||
"playlist_bookmarked": "Afegit a marcadors",
|
||||
"minimize_chapters_default": "Minimitzar capítols per defecte",
|
||||
"skip_button_only": "Mostra el botó de saltar",
|
||||
"skip_automatically": "Automàticament",
|
||||
"min_segment_length": "Longitud de segment mínima (en segons)",
|
||||
"skip_segment": "Saltar segment",
|
||||
"with_playlist": "Comparteix amb llista de reproducció",
|
||||
"show_less": "Mostrar menys"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Fixat per {author}",
|
||||
@ -139,7 +148,9 @@
|
||||
"live": "{0} En Directe",
|
||||
"videos": "Vídeos",
|
||||
"views": "{views} visualitzacions",
|
||||
"shorts": "Curts"
|
||||
"shorts": "Curts",
|
||||
"all": "Tot",
|
||||
"category": "Categoria"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Volies dir: {0}?",
|
||||
@ -169,6 +180,8 @@
|
||||
"preferences_note": "Nota: les preferències es desen a l'emmagatzematge local del navegador. Si elimineu les dades del navegador, es restabliran.",
|
||||
"page_not_found": "No s'ha torbat la pàgina",
|
||||
"copied": "Copiat!",
|
||||
"cannot_copy": "No es pot copiar!"
|
||||
"cannot_copy": "No es pot copiar!",
|
||||
"local_storage": "Aquesta acció requereix emmagatzematge local, estan les cookies habilitades?",
|
||||
"register_no_email_note": "Utilitzar un correu elextrònic com a usuari no és recomanable. Continuar de totes maneres?"
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,10 @@
|
||||
"instance": "Instance",
|
||||
"player": "Přehrávač",
|
||||
"livestreams": "Živé přenosy",
|
||||
"channels": "Kanály"
|
||||
"channels": "Kanály",
|
||||
"bookmarks": "Záložky",
|
||||
"channel_groups": "Skupiny kanálů",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"actions": {
|
||||
"loop_this_video": "Přehrávat video ve smyčce",
|
||||
@ -35,20 +38,20 @@
|
||||
"audio_only": "Pouze zvuk",
|
||||
"default_quality": "Výchozí kvalita",
|
||||
"buffering_goal": "Ukládání do vyrovnávací paměti (v sekundách)",
|
||||
"country_selection": "Výběr země",
|
||||
"country_selection": "Země",
|
||||
"default_homepage": "Výchozí domovská stránka",
|
||||
"show_comments": "Zobrazit komentáře",
|
||||
"minimize_description_default": "Automaticky minimalizovat popis",
|
||||
"store_watch_history": "Ukládat historii sledování",
|
||||
"language_selection": "Výběr jazyka",
|
||||
"language_selection": "Jazyk",
|
||||
"instances_list": "Seznam instancí",
|
||||
"enabled_codecs": "Povolené kodeky (několik)",
|
||||
"instance_selection": "Výběr instance",
|
||||
"instance_selection": "Instance",
|
||||
"show_more": "Zobrazit více",
|
||||
"yes": "Ano",
|
||||
"no": "Ne",
|
||||
"export_to_json": "Exportovat do JSON",
|
||||
"import_from_json": "Importovat z JSON/CSV",
|
||||
"import_from_json": "Importovat z JSON",
|
||||
"auto_play_next_video": "Automaticky přehrát další video",
|
||||
"donations": "Dary na vývoj",
|
||||
"show_description": "Zobrazit popis",
|
||||
@ -59,7 +62,7 @@
|
||||
"disable_lbry": "Zakázat LBRY pro streamování",
|
||||
"enable_lbry_proxy": "Povolit proxy pro LBRY",
|
||||
"view_ssl_score": "Zobrazit stav SSL",
|
||||
"search": "Vyhledat",
|
||||
"search": "Vyhledávání (Ctrl+K)",
|
||||
"filter": "Filtr",
|
||||
"loading": "Načítání...",
|
||||
"clear_history": "Smazat historii",
|
||||
@ -87,7 +90,7 @@
|
||||
"minimize_recommendations_default": "Ve výchozím nastavení minimalizovat doporučení",
|
||||
"invalidate_session": "Odhlásit se ze všech zařízení",
|
||||
"different_auth_instance": "Použít jinou instanci pro autentizaci",
|
||||
"instance_auth_selection": "Výběr autentizační instance",
|
||||
"instance_auth_selection": "Autentizační instance",
|
||||
"clone_playlist": "Duplikovat playlist",
|
||||
"clone_playlist_success": "Úspěšně duplikováno!",
|
||||
"download_as_txt": "Stáhnout jako .txt",
|
||||
@ -102,8 +105,6 @@
|
||||
"follow_link": "Otevřít odkaz",
|
||||
"copy_link": "Kopírovat odkaz",
|
||||
"time_code": "Časový kód (v sekundách)",
|
||||
"rename_playlist": "Přejmenovat playlist",
|
||||
"new_playlist_name": "Nový název playlistu",
|
||||
"show_chapters": "Kapitoly",
|
||||
"store_search_history": "Ukládat historii vyhledávání",
|
||||
"hide_watched": "Skrýt sledovaná videa v kanálu",
|
||||
@ -117,10 +118,35 @@
|
||||
"show_watch_on_youtube": "Zobrazit tlačítko Sledovat na YouTube",
|
||||
"minimize_chapters_default": "Ve výchozím nastavení skrýt kapitoly",
|
||||
"no_valid_playlists": "Soubor neobsahuje platné playlisty!",
|
||||
"with_playlist": "Sdílet s playlistem"
|
||||
"with_playlist": "Sdílet s playlistem",
|
||||
"bookmark_playlist": "Záložka",
|
||||
"playlist_bookmarked": "Uloženo",
|
||||
"skip_automatically": "Automaticky",
|
||||
"skip_segment": "Přeskočit segment",
|
||||
"skip_button_only": "Zobrazit tlačítko přeskočení",
|
||||
"min_segment_length": "Minimální délka segmentu (v sekundách)",
|
||||
"show_less": "Zobrazit méně",
|
||||
"autoplay_next_countdown": "Výchozí odpočet do dalšího videa (v sekundách)",
|
||||
"dismiss": "Zavřít",
|
||||
"group_name": "Název skupiny",
|
||||
"create_group": "Vytvořit skupinu",
|
||||
"auto_display_captions": "Automatické zobrazení titulků",
|
||||
"playlist_name": "Název playlistu",
|
||||
"cancel": "Zrušit",
|
||||
"edit_playlist": "Upravit playlist",
|
||||
"playlist_description": "Popis playlistu",
|
||||
"okay": "Okay",
|
||||
"show_search_suggestions": "Zobrazit našeptávání ve vyhledávání",
|
||||
"chapters_layout_mobile": "Rozložení kapitol na mobilu",
|
||||
"enable_dearrow": "Povolit DeArrow",
|
||||
"delete_automatically": "Automaticky odstranit po",
|
||||
"generate_qrcode": "Vygenerovat QR kód",
|
||||
"import_from_json_csv": "Importovat z JSON/CSV",
|
||||
"download_frame": "Stáhnout snímek"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Sledovat na {0}"
|
||||
"watch_on": "Sledovat na {0}",
|
||||
"failed": "Akce se nezdařila. Chybový kód {0}, pro více informací viz protokol"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Připnuto uživatelem {author}",
|
||||
@ -139,7 +165,9 @@
|
||||
},
|
||||
"login": {
|
||||
"username": "Uživatelské jméno",
|
||||
"password": "Heslo"
|
||||
"password": "Heslo",
|
||||
"password_confirm": "Potvrzení hesla",
|
||||
"passwords_incorrect": "Hesla se neshodují!"
|
||||
},
|
||||
"video": {
|
||||
"videos": "Videa",
|
||||
@ -149,7 +177,13 @@
|
||||
"ratings_disabled": "Hodnocení zakázáno",
|
||||
"chapters": "Kapitoly",
|
||||
"live": "{0} Živě",
|
||||
"shorts": "Shorts"
|
||||
"shorts": "Shorts",
|
||||
"all": "Vše",
|
||||
"category": "Kategorie",
|
||||
"chapters_horizontal": "Horizontální",
|
||||
"chapters_vertical": "Vertikální",
|
||||
"license": "Licence",
|
||||
"visibility": "Viditelnost"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Mysleli jste: {0}?",
|
||||
@ -160,7 +194,8 @@
|
||||
"playlists": "YouTube: Playlisty",
|
||||
"music_videos": "YT Music: Videa",
|
||||
"music_albums": "YT Music: Alba",
|
||||
"music_playlists": "YT Music: Playlisty"
|
||||
"music_playlists": "YT Music: Playlisty",
|
||||
"music_artists": "YT Music: Umělci"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Přihlášeno k odběru: {0}"
|
||||
@ -173,6 +208,12 @@
|
||||
"page_not_found": "Stránka nenalezena",
|
||||
"copied": "Zkopírováno!",
|
||||
"cannot_copy": "Nelze zkopírovat!",
|
||||
"local_storage": "Tato akce vyžaduje localStorage, jsou povoleny cookies?"
|
||||
"local_storage": "Tato akce vyžaduje localStorage, jsou povoleny cookies?",
|
||||
"register_no_email_note": "Použití e-mailu jako uživatelského jména se nedoporučuje. Chcete přesto pokračovat?",
|
||||
"next_video_countdown": "Přehrávání dalšího videa za {0}s",
|
||||
"hours": "{amount} hodin",
|
||||
"days": "{amount} dnů",
|
||||
"weeks": "{amount} týdnů",
|
||||
"months": "{amount} měsíců"
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
{
|
||||
"actions": {
|
||||
"skip_outro": "Abspann überspringen",
|
||||
"skip_non_music": "Musik überspringen: Nicht-Musik-Bereich",
|
||||
"skip_outro": "Endkarten und Abspann überspringen",
|
||||
"skip_non_music": "Musik: Nicht-Musik-Abschnitte überspringen",
|
||||
"skip_self_promo": "Unbezahlte Werbung/Eigenwerbung überspringen",
|
||||
"skip_interaction": "Interaktionserinnerung überspringen (Abonnieren)",
|
||||
"skip_preview": "Vorschau/Rückschau überspringen",
|
||||
"skip_interaction": "Interaktionserinnerungen überspringen (Daumen hoch, abonnieren, ...)",
|
||||
"skip_preview": "Vorschau und Rückblick überspringen",
|
||||
"instances_list": "Liste der Instanzen",
|
||||
"language_selection": "Sprachauswahl",
|
||||
"language_selection": "Sprache",
|
||||
"store_watch_history": "Wiedergabeverlauf speichern",
|
||||
"minimize_description_default": "Beschreibung standardmäßig minimieren",
|
||||
"show_comments": "Kommentare anzeigen",
|
||||
"default_homepage": "Standard-Startseite",
|
||||
"country_selection": "Länderauswahl",
|
||||
"default_homepage": "Startseite",
|
||||
"country_selection": "Land",
|
||||
"buffering_goal": "Pufferungsziel (in Sekunden)",
|
||||
"default_quality": "Standardqualität",
|
||||
"audio_only": "Nur Audio",
|
||||
@ -20,9 +20,9 @@
|
||||
"dark": "Dunkel",
|
||||
"auto": "Automatisch",
|
||||
"theme": "Farbschema",
|
||||
"skip_intro": "Pausen-/Intro-Animation überspringen",
|
||||
"skip_sponsors": "Sponsoren überspringen",
|
||||
"enable_sponsorblock": "Sponsorblock einschalten",
|
||||
"skip_intro": "Unterbrechungen und Intro-Animation überspringen",
|
||||
"skip_sponsors": "Gesponsorte Videoabschnitte überspringen",
|
||||
"enable_sponsorblock": "SponsorBlock verwenden",
|
||||
"uses_api_from": "Verwendet die API von ",
|
||||
"back": "Zurück",
|
||||
"channel_name_desc": "Kanalname (Z-A)",
|
||||
@ -30,53 +30,51 @@
|
||||
"least_recent": "Am wenigsten neu",
|
||||
"most_recent": "Am Neuesten",
|
||||
"sort_by": "Sortieren nach:",
|
||||
"view_subscriptions": "Abonnements anzeigen",
|
||||
"view_subscriptions": "Abos anzeigen",
|
||||
"unsubscribe": "Deabonnieren - {count}",
|
||||
"subscribe": "Abonnieren - {count}",
|
||||
"enabled_codecs": "Aktivierte Codecs (mehrere)",
|
||||
"enabled_codecs": "Aktivierte Codecs (Auswahl mehrerer Codecs möglich)",
|
||||
"enable_lbry_proxy": "Proxy für LBRY einschalten",
|
||||
"disable_lbry": "LBRY für Streaming deaktivieren",
|
||||
"instance_selection": "Instanzauswahl",
|
||||
"instance_selection": "Instanz",
|
||||
"show_description": "Beschreibung anzeigen",
|
||||
"minimize_description": "Beschreibung minimieren",
|
||||
"show_recommendations": "Empfehlungen anzeigen",
|
||||
"minimize_recommendations": "Empfehlungen minimieren",
|
||||
"donations": "Spenden für die Entwickler",
|
||||
"donations": "Spenden",
|
||||
"auto_play_next_video": "Nächstes Video automatisch abspielen",
|
||||
"loop_this_video": "Dieses Video wiederholen",
|
||||
"import_from_json": "Aus JSON/CSV importieren",
|
||||
"import_from_json": "Aus JSON importieren",
|
||||
"export_to_json": "Als JSON exportieren",
|
||||
"show_more": "Mehr anzeigen",
|
||||
"no": "Nein",
|
||||
"yes": "Ja",
|
||||
"loading": "Wird geladen…",
|
||||
"filter": "Filtern",
|
||||
"search": "Suchen",
|
||||
"search": "Suchen (Strg+K)",
|
||||
"view_ssl_score": "SSL-Bewertung anzeigen",
|
||||
"clear_history": "Verlauf löschen",
|
||||
"hide_replies": "Antworten ausblenden",
|
||||
"load_more_replies": "Mehr Antworten laden",
|
||||
"skip_highlight": "Höhepunkt überspringen",
|
||||
"skip_filler_tangent": "Lückenfüller überspringen",
|
||||
"delete_playlist_confirm": "Diese Wiedergabeliste löschen?",
|
||||
"remove_from_playlist": "Aus Wiedergabeliste entfernen",
|
||||
"add_to_playlist": "Zur Wiedergabeliste hinzufügen",
|
||||
"create_playlist": "Wiedergabeliste erstellen",
|
||||
"delete_playlist_video_confirm": "Video aus Wiedergabeliste entfernen?",
|
||||
"delete_playlist": "Wiedergabeliste löschen",
|
||||
"please_select_playlist": "Bitte wählen Sie eine Wiedergabeliste",
|
||||
"select_playlist": "Wählen Sie eine Wiedergabeliste",
|
||||
"delete_playlist_confirm": "Diese Playlist löschen?",
|
||||
"remove_from_playlist": "Aus Playlist entfernen",
|
||||
"add_to_playlist": "Zur Playlist hinzufügen",
|
||||
"create_playlist": "Playlist erstellen",
|
||||
"delete_playlist_video_confirm": "Video aus Playlist entfernen?",
|
||||
"delete_playlist": "Playlist löschen",
|
||||
"please_select_playlist": "Bitte wähle eine Playlist",
|
||||
"select_playlist": "Wähle eine Playlist",
|
||||
"show_markers": "Markierungen auf dem Player anzeigen",
|
||||
"delete_account": "Konto löschen",
|
||||
"logout": "Von diesem Gerät abmelden",
|
||||
"minimize_recommendations_default": "Empfehlungen standardmäßig minimieren",
|
||||
"invalidate_session": "Von allen Geräte abmelden",
|
||||
"invalidate_session": "Von allen Geräten abmelden",
|
||||
"different_auth_instance": "Eine andere Instanz für die Authentifizierung verwenden",
|
||||
"instance_auth_selection": "Auswahl der Autentifizierungsinstanz",
|
||||
"clone_playlist": "Wiedergabeliste klonen",
|
||||
"clone_playlist_success": "Erfolgreich geklont!",
|
||||
"rename_playlist": "Wiedergabeliste umbenennen",
|
||||
"new_playlist_name": "Neuer Name der Wiedergabeliste",
|
||||
"instance_auth_selection": "Authentifizierungsinstanz",
|
||||
"clone_playlist": "Playlist duplizieren",
|
||||
"clone_playlist_success": "Erfolgreich dupliziert!",
|
||||
"piped_link": "Piped-Link",
|
||||
"download_as_txt": "Als .txt herunterladen",
|
||||
"back_to_home": "Zurück zur Startseite",
|
||||
@ -84,7 +82,7 @@
|
||||
"with_timecode": "Mit Zeitstempel teilen",
|
||||
"follow_link": "Link öffnen",
|
||||
"copy_link": "Link kopieren",
|
||||
"time_code": "Zeitstempel (in sekunden)",
|
||||
"time_code": "Zeitstempel (in Sekunden)",
|
||||
"reset_preferences": "Einstellungen zurücksetzen",
|
||||
"confirm_reset_preferences": "Bist du sicher, dass du deine Einstellungen zurücksetzen möchtest?",
|
||||
"backup_preferences": "Einstellungen sichern",
|
||||
@ -92,45 +90,79 @@
|
||||
"show_chapters": "Kapitel",
|
||||
"source_code": "Quellcode",
|
||||
"store_search_history": "Suchverlauf speichern",
|
||||
"hide_watched": "Gesehene Videos im Feed ausblenden",
|
||||
"hide_watched": "Gesehene Videos im Abo-Feed ausblenden",
|
||||
"reply_count": "{count} Antworten",
|
||||
"instance_donations": "Instanz-Spenden",
|
||||
"documentation": "Dokumentation",
|
||||
"status_page": "Status",
|
||||
"minimize_chapters_default": "Kapitel standardmäßig minimieren",
|
||||
"minimize_comments_default": "Kommentare automatisch minimieren",
|
||||
"minimize_comments_default": "Kommentare standardmäßig minimieren",
|
||||
"minimize_comments": "Kommentare minimieren",
|
||||
"no_valid_playlists": "Die Datei enthält keine gültigen Wiedergabelisten!",
|
||||
"no_valid_playlists": "Die Datei enthält keine gültigen Playlists!",
|
||||
"show_watch_on_youtube": "Schaltfläche „Auf YouTube ansehen“ anzeigen",
|
||||
"with_playlist": "Mit Wiedergabeliste teilen"
|
||||
"with_playlist": "Mit Playlist teilen",
|
||||
"playlist_bookmarked": "Markiert",
|
||||
"bookmark_playlist": "Lesezeichen",
|
||||
"skip_segment": "Abschnitt überspringen",
|
||||
"skip_automatically": "Automatisch",
|
||||
"min_segment_length": "Minimale Abschnittlänge (in Sekunden)",
|
||||
"skip_button_only": "Überspringen-Schaltfläche anzeigen",
|
||||
"show_less": "Weniger anzeigen",
|
||||
"autoplay_next_countdown": "Anzahl der Sekunden bis das nächste Video automatisch startet",
|
||||
"dismiss": "Ablehnen",
|
||||
"group_name": "Gruppenname",
|
||||
"create_group": "Gruppe erstellen",
|
||||
"auto_display_captions": "Untertitel automatisch anzeigen",
|
||||
"cancel": "Abbrechen",
|
||||
"okay": "Okay",
|
||||
"edit_playlist": "Playlist bearbeiten",
|
||||
"playlist_name": "Name der Playlist",
|
||||
"playlist_description": "Beschreibung der Playlist",
|
||||
"show_search_suggestions": "Suchvorschläge anzeigen",
|
||||
"chapters_layout_mobile": "Kapitel-Layout auf Mobilgeräten",
|
||||
"delete_automatically": "Automatisch löschen nach",
|
||||
"enable_dearrow": "DeArrow verwenden",
|
||||
"generate_qrcode": "QR-Code generieren",
|
||||
"import_from_json_csv": "Aus JSON/CSV importieren",
|
||||
"download_frame": "Einzelbild (Frame) downloaden"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Auf {0} ansehen"
|
||||
"watch_on": "Auf {0} ansehen",
|
||||
"failed": "Fehlgeschlagen mit Fehlercode {0}, siehe Protokolle für weitere Informationen"
|
||||
},
|
||||
"titles": {
|
||||
"history": "Verlauf",
|
||||
"preferences": "Einstellungen",
|
||||
"feed": "Abonnements",
|
||||
"feed": "Abos",
|
||||
"register": "Registrieren",
|
||||
"login": "Anmelden",
|
||||
"trending": "Trends",
|
||||
"subscriptions": "Abonnements",
|
||||
"playlists": "Wiedergabelisten",
|
||||
"subscriptions": "Abos",
|
||||
"playlists": "Playlists",
|
||||
"account": "Konto",
|
||||
"player": "Player",
|
||||
"instance": "Instanz",
|
||||
"livestreams": "Livestreams",
|
||||
"channels": "Kanäle"
|
||||
"channels": "Kanäle",
|
||||
"bookmarks": "Lesezeichen",
|
||||
"channel_groups": "Kanalgruppen",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"video": {
|
||||
"sponsor_segments": "Sponsoren-Segmente",
|
||||
"sponsor_segments": "Sponsoren-Abschnitte",
|
||||
"watched": "Angesehen",
|
||||
"views": "{views} Aufrufe",
|
||||
"videos": "Videos",
|
||||
"ratings_disabled": "Bewertungen deaktiviert",
|
||||
"live": "{0} Live",
|
||||
"chapters": "Kapitel",
|
||||
"shorts": "Shorts"
|
||||
"shorts": "Shorts",
|
||||
"all": "Alle",
|
||||
"category": "Kategorie",
|
||||
"chapters_horizontal": "Horizontal",
|
||||
"chapters_vertical": "Vertikal",
|
||||
"license": "Lizenz",
|
||||
"visibility": "Sichtbarkeit"
|
||||
},
|
||||
"preferences": {
|
||||
"ssl_score": "SSL-Bewertung",
|
||||
@ -145,31 +177,40 @@
|
||||
"pinned_by": "Angeheftet von {author}",
|
||||
"user_disabled": "Kommentare wurden in den Einstellungen deaktiviert.",
|
||||
"disabled": "Kommentare wurden vom Autor deaktiviert.",
|
||||
"loading": "Kommentare werden geladen …"
|
||||
"loading": "Kommentare werden geladen…"
|
||||
},
|
||||
"login": {
|
||||
"password": "Passwort",
|
||||
"username": "Anmeldename"
|
||||
"username": "Benutzername",
|
||||
"password_confirm": "Passwort bestätigen",
|
||||
"passwords_incorrect": "Passwörter stimmen nicht überein!"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Hast du gemeint: {0}?",
|
||||
"all": "YouTube: Alle",
|
||||
"videos": "YouTube: Videos",
|
||||
"channels": "YouTube: Kanäle",
|
||||
"playlists": "YouTube: Wiedergabelisten",
|
||||
"playlists": "YouTube: Playlists",
|
||||
"music_songs": "YT Music: Lieder",
|
||||
"music_videos": "YT Music: Videos",
|
||||
"music_albums": "YT Music: Alben",
|
||||
"music_playlists": "YT Music: Wiedergabelisten"
|
||||
"music_playlists": "YT Music: Playlists",
|
||||
"music_artists": "YT Music: Künstler:innen"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Aboniert bei: {0}"
|
||||
"subscribed_channels_count": "Anzahl Abos: {0}"
|
||||
},
|
||||
"info": {
|
||||
"preferences_note": "Achtung: Einstellung werden lokal in deinem Browser gespeichert. Wenn du deine Browserdaten löschst werden sie auch gelöscht.",
|
||||
"preferences_note": "Achtung: Die Einstellungen werden lokal in deinem Browser gespeichert. Wenn du deine Browserdaten löschst, werden auch deine Einstellungen zurückgesetzt.",
|
||||
"page_not_found": "Seite nicht gefunden",
|
||||
"copied": "Kopiert!",
|
||||
"cannot_copy": "Kopieren nicht möglich!",
|
||||
"local_storage": "Diese Aktion erfordert „localStorage“, sind Cookies aktiviert?"
|
||||
"local_storage": "Diese Aktion erfordert „localStorage“, sind Cookies aktiviert?",
|
||||
"register_no_email_note": "Es wird nicht empfohlen, eine E-Mail als Benutzernamen zu verwenden. Trotzdem fortfahren?",
|
||||
"next_video_countdown": "Nächstes Video startet in {0}s",
|
||||
"weeks": "{amount} Woche(n)",
|
||||
"months": "{amount} Monat(en)",
|
||||
"hours": "{amount} Stunde(n)",
|
||||
"days": "{amount} Tag(e)"
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,14 @@
|
||||
"instance": "Instance",
|
||||
"player": "Player",
|
||||
"livestreams": "Livestreams",
|
||||
"channels": "Channels"
|
||||
"channels": "Channels",
|
||||
"bookmarks": "Bookmarks",
|
||||
"channel_groups": "Channel groups",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Watch on {0}"
|
||||
"watch_on": "Watch on {0}",
|
||||
"failed": "Failed with error code {0}, see logs for more info"
|
||||
},
|
||||
"actions": {
|
||||
"subscribe": "Subscribe - {count}",
|
||||
@ -29,6 +33,8 @@
|
||||
"back": "Back",
|
||||
"uses_api_from": "Uses the API from ",
|
||||
"enable_sponsorblock": "Enable Sponsorblock",
|
||||
"skip_button_only": "Show skip button",
|
||||
"skip_automatically": "Automatically",
|
||||
"skip_sponsors": "Skip Sponsors",
|
||||
"skip_intro": "Skip Intermission/Intro Animation",
|
||||
"skip_outro": "Skip Endcards/Credits",
|
||||
@ -39,30 +45,36 @@
|
||||
"skip_highlight": "Skip Highlight",
|
||||
"skip_filler_tangent": "Skip Filler Tangent",
|
||||
"show_markers": "Show Markers on Player",
|
||||
"min_segment_length": "Minimum Segment Length (in seconds)",
|
||||
"skip_segment": "Skip Segment",
|
||||
"enable_dearrow": "Enable DeArrow",
|
||||
"theme": "Theme",
|
||||
"auto": "Auto",
|
||||
"dark": "Dark",
|
||||
"light": "Light",
|
||||
"autoplay_video": "Autoplay Video",
|
||||
"autoplay_next_countdown": "Default Countdown until next video (in seconds)",
|
||||
"audio_only": "Audio Only",
|
||||
"default_quality": "Default Quality",
|
||||
"buffering_goal": "Buffering Goal (in seconds)",
|
||||
"country_selection": "Country Selection",
|
||||
"country_selection": "Country",
|
||||
"default_homepage": "Default Homepage",
|
||||
"minimize_comments_default": "Minimize Comments by default",
|
||||
"minimize_description_default": "Minimize Description by default",
|
||||
"store_watch_history": "Store Watch History",
|
||||
"language_selection": "Language Selection",
|
||||
"language_selection": "Language",
|
||||
"instances_list": "Instances List",
|
||||
"enabled_codecs": "Enabled Codecs (Multiple)",
|
||||
"instance_selection": "Instance Selection",
|
||||
"instance_selection": "Instance",
|
||||
"show_more": "Show More",
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
"export_to_json": "Export to JSON",
|
||||
"import_from_json": "Import from JSON/CSV",
|
||||
"import_from_json": "Import from JSON",
|
||||
"import_from_json_csv": "Import from JSON/CSV",
|
||||
"loop_this_video": "Loop this Video",
|
||||
"auto_play_next_video": "Auto Play next Video",
|
||||
"auto_display_captions": "Auto Display Captions",
|
||||
"donations": "Development donations",
|
||||
"minimize_comments": "Minimize Comments",
|
||||
"show_comments": "Comments",
|
||||
@ -73,7 +85,7 @@
|
||||
"disable_lbry": "Disable LBRY for Streaming",
|
||||
"enable_lbry_proxy": "Enable Proxy for LBRY",
|
||||
"view_ssl_score": "View SSL Score",
|
||||
"search": "Search",
|
||||
"search": "Search (Ctrl+K)",
|
||||
"filter": "Filter",
|
||||
"loading": "Loading...",
|
||||
"clear_history": "Clear History",
|
||||
@ -91,10 +103,11 @@
|
||||
"logout": "Logout from this device",
|
||||
"minimize_recommendations_default": "Minimize Recommendations by default",
|
||||
"minimize_chapters_default": "Minimize Chapters by default",
|
||||
"chapters_layout_mobile": "Chapters Layout On Mobile",
|
||||
"show_watch_on_youtube": "Show Watch on YouTube button",
|
||||
"invalidate_session": "Logout all devices",
|
||||
"different_auth_instance": "Use a different instance for authentication",
|
||||
"instance_auth_selection": "Autentication Instance Selection",
|
||||
"instance_auth_selection": "Authentication Instance",
|
||||
"clone_playlist": "Clone Playlist",
|
||||
"clone_playlist_success": "Successfully cloned!",
|
||||
"download_as_txt": "Download as .txt",
|
||||
@ -103,8 +116,9 @@
|
||||
"backup_preferences": "Backup preferences",
|
||||
"restore_preferences": "Restore preferences",
|
||||
"back_to_home": "Back to home",
|
||||
"rename_playlist": "Rename",
|
||||
"new_playlist_name": "New playlist name",
|
||||
"edit_playlist": "Edit",
|
||||
"playlist_name": "Playlist name",
|
||||
"playlist_description": "Playlist description",
|
||||
"share": "Share",
|
||||
"with_timecode": "Share with time code",
|
||||
"piped_link": "Piped link",
|
||||
@ -112,7 +126,7 @@
|
||||
"copy_link": "Copy link",
|
||||
"time_code": "Time code (in seconds)",
|
||||
"show_chapters": "Chapters",
|
||||
"store_search_history": "Store Search history",
|
||||
"store_search_history": "Store Search History",
|
||||
"hide_watched": "Hide watched videos in the feed",
|
||||
"documentation": "Documentation",
|
||||
"status_page": "Status",
|
||||
@ -120,7 +134,19 @@
|
||||
"instance_donations": "Instance donations",
|
||||
"reply_count": "{count} replies",
|
||||
"no_valid_playlists": "The file doesn't contain valid playlists!",
|
||||
"with_playlist": "Share with playlist"
|
||||
"with_playlist": "Share with playlist",
|
||||
"bookmark_playlist": "Bookmark",
|
||||
"playlist_bookmarked": "Bookmarked",
|
||||
"dismiss": "Dismiss",
|
||||
"show_less": "Show less",
|
||||
"create_group": "Create group",
|
||||
"group_name": "Group name",
|
||||
"cancel": "Cancel",
|
||||
"okay": "Okay",
|
||||
"show_search_suggestions": "Show search suggestions",
|
||||
"delete_automatically": "Delete automatically after",
|
||||
"generate_qrcode": "Generate QR Code",
|
||||
"download_frame": "Download frame"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Pinned by {author}",
|
||||
@ -139,7 +165,9 @@
|
||||
},
|
||||
"login": {
|
||||
"username": "Username",
|
||||
"password": "Password"
|
||||
"password": "Password",
|
||||
"password_confirm": "Confirm password",
|
||||
"passwords_incorrect": "Passwords don't match!"
|
||||
},
|
||||
"video": {
|
||||
"videos": "Videos",
|
||||
@ -149,7 +177,13 @@
|
||||
"ratings_disabled": "Ratings Disabled",
|
||||
"chapters": "Chapters",
|
||||
"live": "{0} Live",
|
||||
"shorts": "Shorts"
|
||||
"shorts": "Shorts",
|
||||
"all": "All",
|
||||
"category": "Category",
|
||||
"license": "License",
|
||||
"visibility": "Visibility",
|
||||
"chapters_horizontal": "Horizontal",
|
||||
"chapters_vertical": "Vertical"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Did you mean: {0}?",
|
||||
@ -160,7 +194,8 @@
|
||||
"music_songs": "YT Music: Songs",
|
||||
"music_videos": "YT Music: Videos",
|
||||
"music_albums": "YT Music: Albums",
|
||||
"music_playlists": "YT Music: Playlists"
|
||||
"music_playlists": "YT Music: Playlists",
|
||||
"music_artists": "YT Music: Artists"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Subscribed to: {0}"
|
||||
@ -170,6 +205,12 @@
|
||||
"page_not_found": "Page not found",
|
||||
"copied": "Copied!",
|
||||
"cannot_copy": "Can't copy!",
|
||||
"local_storage": "This action requires localStorage, are cookies enabled?"
|
||||
"local_storage": "This action requires localStorage, are cookies enabled?",
|
||||
"register_no_email_note": "Using an e-mail as username is not recommended. Proceed anyways?",
|
||||
"next_video_countdown": "Playing next video in {0}s",
|
||||
"hours": "{amount} hour(s)",
|
||||
"days": "{amount} day(s)",
|
||||
"weeks": "{amount} week(s)",
|
||||
"months": "{amount} month(s)"
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,14 @@
|
||||
"player": "Ludilo",
|
||||
"instance": "Nodo",
|
||||
"channels": "Kanaloj",
|
||||
"livestreams": "Tujelsendoj"
|
||||
"livestreams": "Tujelsendoj",
|
||||
"bookmarks": "Legosignoj",
|
||||
"channel_groups": "Kanalaroj",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Vidi en {0}"
|
||||
"watch_on": "Vidi en {0}",
|
||||
"failed": "Fiaskis kun erarkodo {0}, vidu protokolojn por pli da informo"
|
||||
},
|
||||
"actions": {
|
||||
"subscribe": "Aboni - {count}",
|
||||
@ -38,22 +42,21 @@
|
||||
"light": "Hela",
|
||||
"autoplay_video": "Aŭtomate Ludi Videon",
|
||||
"audio_only": "Nur Sono",
|
||||
"default_quality": "Defaŭlta Kvalito",
|
||||
"country_selection": "Landa Elekto",
|
||||
"default_homepage": "Defaŭlta Ĉefpaĝo",
|
||||
"default_quality": "Implicita Kvalito",
|
||||
"country_selection": "Lando",
|
||||
"default_homepage": "Implicita Ĉefpaĝo",
|
||||
"show_comments": "Montri Komentojn",
|
||||
"language_selection": "Lingva Elekto",
|
||||
"language_selection": "Lingvo",
|
||||
"donations": "Donacoj por programado",
|
||||
"show_more": "Montri Pli",
|
||||
"show_more": "Montri pli",
|
||||
"yes": "Jes",
|
||||
"no": "Ne",
|
||||
"show_chapters": "Sekcioj",
|
||||
"filter": "Filtri",
|
||||
"search": "Serĉi",
|
||||
"search": "Serĉi (Ctrl+K)",
|
||||
"hide_replies": "Kaŝi Respondojn",
|
||||
"add_to_playlist": "Aldoni al ludlisto",
|
||||
"delete_playlist": "Forigi Ludliston",
|
||||
"rename_playlist": "Renomi ludliston",
|
||||
"download_as_txt": "Elŝuti kiel .txt",
|
||||
"piped_link": "Piped-ligilo",
|
||||
"copy_link": "Kopii ligilon",
|
||||
@ -66,7 +69,6 @@
|
||||
"remove_from_playlist": "Forigi el ludlisto",
|
||||
"create_playlist": "Krei Ludliston",
|
||||
"delete_account": "Forigi Konton",
|
||||
"new_playlist_name": "Nomo de nova ludlisto",
|
||||
"reply_count": "{count} respondoj",
|
||||
"load_more_replies": "Ŝargi pli da Respondoj",
|
||||
"share": "Konigi",
|
||||
@ -77,13 +79,13 @@
|
||||
"export_to_json": "Elporti JSON-n",
|
||||
"loop_this_video": "Ripetadi ĉi tiun Videon",
|
||||
"enable_lbry_proxy": "Ebligi Prokurilon por LBRY",
|
||||
"import_from_json": "Importi el JSON/CSV",
|
||||
"import_from_json": "Importi el JSON",
|
||||
"show_description": "Montri Priskribon",
|
||||
"instances_list": "Listo de Nodoj",
|
||||
"auto_play_next_video": "Aŭtomate Ludi sekvan Videon",
|
||||
"show_recommendations": "Montri Rekomendojn",
|
||||
"reset_preferences": "Restarigi agordojn",
|
||||
"instance_selection": "Noda Elekto",
|
||||
"instance_selection": "Nodo",
|
||||
"view_ssl_score": "Vidu SSL-Poentaron",
|
||||
"backup_preferences": "Savkopii agordojn",
|
||||
"disable_lbry": "Malebligi LBRY-n por Elsendfluo",
|
||||
@ -91,7 +93,7 @@
|
||||
"store_search_history": "Konservi Ŝerĉhistorion",
|
||||
"hide_watched": "Kaŝi viditajn videojn en la fluo",
|
||||
"minimize_recommendations": "Plejetigi Rekomendojn",
|
||||
"instance_auth_selection": "Elekto de Aŭtentokontrola Nodo",
|
||||
"instance_auth_selection": "Aŭtentokontrola nodo",
|
||||
"restore_preferences": "Restarigi agordojn",
|
||||
"status_page": "Stato",
|
||||
"please_select_playlist": "Bonvolu elekti ludliston",
|
||||
@ -113,14 +115,38 @@
|
||||
"skip_interaction": "Preterpasi Interagan Memorigon (Aboni)",
|
||||
"store_watch_history": "Konservi Vidhistorion",
|
||||
"logout": "Elsaluti el ĉi tiu aparato",
|
||||
"minimize_description_default": "Defaŭlte Plejetigi Priskribon",
|
||||
"minimize_recommendations_default": "Defaŭlte Plejetigi Rekomendojn",
|
||||
"minimize_comments_default": "Defaŭlte Plejetigi Komentojn",
|
||||
"minimize_description_default": "Implicite Plejetigi Priskribon",
|
||||
"minimize_recommendations_default": "Implicite Plejetigi Rekomendojn",
|
||||
"minimize_comments_default": "Implicite Plejetigi Komentojn",
|
||||
"minimize_comments": "Plejetigi Komentojn",
|
||||
"show_watch_on_youtube": "Montri «Vidi en Youtube»-butonon",
|
||||
"minimize_chapters_default": "Defaŭlte plejetigi ĉapitrojn",
|
||||
"minimize_chapters_default": "Implicite plejetigi ĉapitrojn",
|
||||
"no_valid_playlists": "La dosiero ne enhavas validajn ludlistojn!",
|
||||
"with_playlist": "Konigi kun ludlisto"
|
||||
"with_playlist": "Konigi kun ludlisto",
|
||||
"playlist_bookmarked": "Legosignita",
|
||||
"bookmark_playlist": "Legosigno",
|
||||
"skip_automatically": "Aŭtomate",
|
||||
"skip_button_only": "Montri preterpasi-butonon",
|
||||
"min_segment_length": "Minimuma Segmenta Daŭro (en sekundoj)",
|
||||
"skip_segment": "Preterpasi Segmenton",
|
||||
"show_less": "Montri malpli",
|
||||
"dismiss": "Nuligi",
|
||||
"autoplay_next_countdown": "Implicita retronombrado ĝis sekva video (en sekundoj)",
|
||||
"group_name": "Nomo de la aro",
|
||||
"create_group": "Krei aron",
|
||||
"auto_display_captions": "Aŭtomate montri subtekstojn",
|
||||
"playlist_name": "Nomo de la ludlisto",
|
||||
"edit_playlist": "Redakti ludliston",
|
||||
"okay": "Bone",
|
||||
"playlist_description": "Priskribo de la ludlisto",
|
||||
"cancel": "Nuligi",
|
||||
"show_search_suggestions": "Montri serĉ-sugestojn",
|
||||
"chapters_layout_mobile": "Aranĝo de ĉapitroj en poŝtelefono",
|
||||
"delete_automatically": "Aŭtomate forigi post",
|
||||
"enable_dearrow": "Ebligi DeArrow",
|
||||
"generate_qrcode": "Generi QR-kodon",
|
||||
"import_from_json_csv": "Importi el JSON/CSV",
|
||||
"download_frame": "Elŝuti bildon"
|
||||
},
|
||||
"video": {
|
||||
"chapters": "Sekcioj",
|
||||
@ -128,9 +154,15 @@
|
||||
"live": "{0} Realtempe",
|
||||
"views": "{views} spektoj",
|
||||
"sponsor_segments": "Sponsoraj Segmentoj",
|
||||
"watched": "Viditaj",
|
||||
"watched": "Spektita",
|
||||
"ratings_disabled": "Taksadoj Malebligitaj",
|
||||
"shorts": "Mallongaj"
|
||||
"shorts": "Mallongaj",
|
||||
"all": "Ĉiuj",
|
||||
"category": "Kategorio",
|
||||
"chapters_horizontal": "Horizontala",
|
||||
"chapters_vertical": "Vertikala",
|
||||
"license": "Permesilo",
|
||||
"visibility": "Videbleco"
|
||||
},
|
||||
"search": {
|
||||
"music_albums": "YT Music: Albumoj",
|
||||
@ -141,18 +173,27 @@
|
||||
"music_videos": "YT Music: Videoj",
|
||||
"music_songs": "YT Music: Muzikaĵoj",
|
||||
"all": "YouTube: Ĉio",
|
||||
"did_you_mean": "Ĉu vi volis diri «{0}»?"
|
||||
"did_you_mean": "Ĉu vi volis diri «{0}»?",
|
||||
"music_artists": "YT Music: Artistoj"
|
||||
},
|
||||
"info": {
|
||||
"copied": "Kopiita!",
|
||||
"cannot_copy": "Ne povas kopii!",
|
||||
"preferences_note": "Noto: la agordoj estas konservitaj en la loka memoro de via retumilo. Forigi la datumojn de via retumilo restarigos ilin.",
|
||||
"page_not_found": "Paĝo ne trovita",
|
||||
"local_storage": "Ĉi tiu ago postulas localStorage, ĉu kuketoj estas ebligitaj?"
|
||||
"local_storage": "Ĉi tiu ago postulas localStorage, ĉu kuketoj estas ebligitaj?",
|
||||
"register_no_email_note": "Uzi retadreson kiel uzantnomon ne estas rekomendita. Ĉu daŭrigi ĉiuokaze?",
|
||||
"next_video_countdown": "Oni ludos la sekvan videon post {0}s",
|
||||
"hours": "{amount} horo(j)",
|
||||
"days": "{amount} tago(j)",
|
||||
"weeks": "{amount} semajno(j)",
|
||||
"months": "{amount} monato(j)"
|
||||
},
|
||||
"login": {
|
||||
"username": "Uzantnomo",
|
||||
"password": "Pasvorto"
|
||||
"password": "Pasvorto",
|
||||
"password_confirm": "Konfirmu la pasvorton",
|
||||
"passwords_incorrect": "Pasvortoj ne kongruas!"
|
||||
},
|
||||
"preferences": {
|
||||
"version": "Versio",
|
||||
|
@ -7,7 +7,13 @@
|
||||
"ratings_disabled": "Valoraciones Desactivadas",
|
||||
"chapters": "Capítulos",
|
||||
"live": "{0} Directo",
|
||||
"shorts": "Cortos"
|
||||
"shorts": "Cortos",
|
||||
"all": "Todos",
|
||||
"category": "Categoría",
|
||||
"chapters_horizontal": "Horizontal",
|
||||
"chapters_vertical": "Vertical",
|
||||
"license": "Licencia",
|
||||
"visibility": "Visibilidad"
|
||||
},
|
||||
"preferences": {
|
||||
"ssl_score": "Puntuación SSL",
|
||||
@ -32,20 +38,20 @@
|
||||
"donations": "Donaciones para desarrollo",
|
||||
"auto_play_next_video": "Reproducción automática del siguiente vídeo",
|
||||
"loop_this_video": "Poner en bucle este vídeo",
|
||||
"import_from_json": "Importar desde JSON/CSV",
|
||||
"import_from_json": "Importar desde JSON",
|
||||
"export_to_json": "Exportar a JSON",
|
||||
"no": "No",
|
||||
"yes": "Sí",
|
||||
"show_more": "Mostrar más",
|
||||
"instance_selection": "Selección de instancias",
|
||||
"instance_selection": "Instancia",
|
||||
"enabled_codecs": "Códecs habilitados (múltiples)",
|
||||
"instances_list": "Lista de instancias",
|
||||
"language_selection": "Selección de lenguajes",
|
||||
"language_selection": "Idioma",
|
||||
"store_watch_history": "Recordar historial de visualización",
|
||||
"minimize_description_default": "Minimizar la descripción por defecto",
|
||||
"show_comments": "Mostrar comentarios",
|
||||
"default_homepage": "Página de inicio predeterminada",
|
||||
"country_selection": "Selección de países",
|
||||
"country_selection": "País",
|
||||
"buffering_goal": "Objetivo de amortiguación (en segundos)",
|
||||
"default_quality": "Calidad predeterminada",
|
||||
"audio_only": "Sólo audio",
|
||||
@ -74,7 +80,7 @@
|
||||
"subscribe": "Suscribirme - {count}",
|
||||
"loading": "Cargando…",
|
||||
"filter": "Filtrar",
|
||||
"search": "Buscar",
|
||||
"search": "Buscar (Ctrl+K)",
|
||||
"view_ssl_score": "Ver la puntuación SSL",
|
||||
"minimize_recommendations": "Minimizar recomendaciones",
|
||||
"show_recommendations": "Mostrar recomendaciones",
|
||||
@ -89,8 +95,8 @@
|
||||
"create_playlist": "Crear una lista de reproducción",
|
||||
"add_to_playlist": "Añadir a la lista de reproducción",
|
||||
"delete_playlist_video_confirm": "¿Eliminar vídeo de lista de reproducción?",
|
||||
"please_select_playlist": "Seleccione una lista de reproducción",
|
||||
"select_playlist": "Seleccione una lista de reproducción",
|
||||
"please_select_playlist": "Por favor, selecciona una lista de reproducción",
|
||||
"select_playlist": "Selecciona una lista de reproducción",
|
||||
"show_markers": "Mostrar Marcadores en Reproductor",
|
||||
"delete_account": "Eliminar Cuenta",
|
||||
"different_auth_instance": "Usar una instancia diferente para autenticación",
|
||||
@ -99,10 +105,8 @@
|
||||
"logout": "Cerrar sesión en este dispositivo",
|
||||
"minimize_recommendations_default": "Minimizar Recomendaciones por defecto",
|
||||
"invalidate_session": "Cerrar sesión en todos los dispositivos",
|
||||
"instance_auth_selection": "Selección de la Instancia de Autentificación",
|
||||
"instance_auth_selection": "Instancia de autenticación",
|
||||
"download_as_txt": "Descargar como .txt",
|
||||
"rename_playlist": "Cambiar el nombre de la lista de reproducción",
|
||||
"new_playlist_name": "Nuevo nombre de la lista de reproducción",
|
||||
"share": "Compartir",
|
||||
"with_timecode": "Compartir con código de tiempo",
|
||||
"piped_link": "Enlace de Piped",
|
||||
@ -115,7 +119,7 @@
|
||||
"restore_preferences": "Restablecer las preferencias",
|
||||
"back_to_home": "Volver a la página de inicio",
|
||||
"show_chapters": "Capítulos",
|
||||
"store_search_history": "Guardar historial de búsqueda",
|
||||
"store_search_history": "Guardar el historial de las búsquedas",
|
||||
"source_code": "Código fuente",
|
||||
"documentation": "Documentación",
|
||||
"instance_donations": "Donaciones para instancia",
|
||||
@ -127,10 +131,34 @@
|
||||
"show_watch_on_youtube": "Mostrar botón Ver en YouTube",
|
||||
"minimize_chapters_default": "Minimiza capítulos por defecto",
|
||||
"no_valid_playlists": "¡El archivo no contiene listas de reproducción válidas!",
|
||||
"with_playlist": "Compartir con lista de reproducción"
|
||||
"with_playlist": "Compartir con lista de reproducción",
|
||||
"playlist_bookmarked": "Marcado",
|
||||
"bookmark_playlist": "Marcador",
|
||||
"skip_button_only": "Muestra botón de saltar",
|
||||
"skip_automatically": "Automáticamente",
|
||||
"min_segment_length": "Mínima Duración de Segmento (en segundos)",
|
||||
"skip_segment": "Saltar Segmento",
|
||||
"show_less": "Mostrar menos",
|
||||
"autoplay_next_countdown": "Cuenta atrás predeterminada antes del siguiente vídeo (en segundos)",
|
||||
"dismiss": "Descartar",
|
||||
"group_name": "Nombre del grupo",
|
||||
"create_group": "Crear grupo",
|
||||
"auto_display_captions": "Mostrar automáticamente subtítulos",
|
||||
"edit_playlist": "Editar lista de reproducción",
|
||||
"okay": "Vale",
|
||||
"playlist_name": "Nombre de la lista de reproducción",
|
||||
"playlist_description": "Descripción de la lista de reproducción",
|
||||
"cancel": "Cancelar",
|
||||
"show_search_suggestions": "Mostrar sugerencias de búsqueda",
|
||||
"chapters_layout_mobile": "Disposición de capítulos en móvil",
|
||||
"delete_automatically": "Borrar automáticamente después de",
|
||||
"enable_dearrow": "Activar DeArrow",
|
||||
"generate_qrcode": "Generar código QR",
|
||||
"import_from_json_csv": "Importar desde JSON/CSV",
|
||||
"download_frame": "Descargar fotograma"
|
||||
},
|
||||
"titles": {
|
||||
"feed": "Fuente web",
|
||||
"feed": "Contenido",
|
||||
"subscriptions": "Suscripciones",
|
||||
"history": "Historial",
|
||||
"trending": "En tendencias",
|
||||
@ -142,14 +170,20 @@
|
||||
"instance": "Instancia",
|
||||
"player": "Reproductor",
|
||||
"livestreams": "Directos",
|
||||
"channels": "Canales"
|
||||
"channels": "Canales",
|
||||
"bookmarks": "Marcadores",
|
||||
"channel_groups": "Grupos de canales",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Ver en {0}"
|
||||
"watch_on": "Ver en {0}",
|
||||
"failed": "Falló con el código de error {0}, consulta los registros para más información"
|
||||
},
|
||||
"login": {
|
||||
"password": "Contraseña",
|
||||
"username": "Nombre de usuario"
|
||||
"username": "Nombre de usuario",
|
||||
"passwords_incorrect": "¡Las contraseñas no coinciden!",
|
||||
"password_confirm": "Confirma la contraseña"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "¿Quisiste decir {0}?",
|
||||
@ -160,7 +194,8 @@
|
||||
"videos": "YouTube: Vídeos",
|
||||
"channels": "YouTube: Canales",
|
||||
"playlists": "YouTube: Listas de reproducción",
|
||||
"music_albums": "YT Music: Álbumes"
|
||||
"music_albums": "YT Music: Álbumes",
|
||||
"music_artists": "YT Music: Artistas"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Suscrito a: {0}"
|
||||
@ -170,6 +205,12 @@
|
||||
"page_not_found": "Página no encontrada",
|
||||
"copied": "¡Copiado!",
|
||||
"cannot_copy": "¡No se puede copiar!",
|
||||
"local_storage": "Esta acción requiere «localStorage», ¿están activadas las «cookies»?"
|
||||
"local_storage": "Esta acción requiere «localStorage», ¿están activadas las «cookies»?",
|
||||
"register_no_email_note": "No se recomienda usar un correo electrónico como nombre de usuario. ¿Continuar de todos modos?",
|
||||
"next_video_countdown": "El próximo vídeo se reproducirá en {0}s",
|
||||
"hours": "{amount} hora(s)",
|
||||
"days": "{amount} día(s)",
|
||||
"weeks": "{amount} semana(s)",
|
||||
"months": "{amount} mes(es)"
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@
|
||||
"import_from_json": "وارد کردن از JSON/CSV",
|
||||
"export_to_json": "دادن خروجی با فرمت JSON",
|
||||
"show_description": "نمایش توضیحات ویدئو",
|
||||
"donations": "کمک های مالی",
|
||||
"donations": "کمک های مالی برای توسعه",
|
||||
"clear_history": "تخلیه تاریخچه",
|
||||
"loop_this_video": "تکرار شدن این ویدئو",
|
||||
"auto_play_next_video": "پخش خودکار ویدئو بعدی",
|
||||
@ -57,16 +57,43 @@
|
||||
"hide_replies": "پنهان کردن پاسخ ها",
|
||||
"load_more_replies": "بارگذاری پاسخ های بیشتر",
|
||||
"disable_lbry": "غیرفعال کردن LBRY برای استریم ها",
|
||||
"enable_lbry_proxy": "فعال کردن پراکسی برای LBRY"
|
||||
"enable_lbry_proxy": "فعال کردن پراکسی برای LBRY",
|
||||
"delete_playlist": "حذف لیست پخش",
|
||||
"show_markers": "نشانگر را روی پخش کننده نشان دهد",
|
||||
"select_playlist": "انتخاب لیست پخش",
|
||||
"add_to_playlist": "افزودن به لیست پخش",
|
||||
"create_playlist": "ایجاد لیست پخش",
|
||||
"delete_playlist_confirm": "این لیست پخش حذف شود؟",
|
||||
"delete_account": "حذف اکانت",
|
||||
"logout": "خروج از این دستگاه",
|
||||
"delete_playlist_video_confirm": "ویدیو از لیست پخش حذف شود؟",
|
||||
"autoplay_next_countdown": "پیشفرض شمارشمعکوس پخش ویدیوی بعدی ( به ثانیه )",
|
||||
"please_select_playlist": "انتخاب لیست پخش",
|
||||
"minimize_comments_default": "کوچک کردن کامنتها به صورت پیش فرض",
|
||||
"minimize_comments": "کوچک کردن کامنت (نظرات)",
|
||||
"remove_from_playlist": "حذف از لیست پخش",
|
||||
"skip_button_only": "دکمهی گذر را نشان بده",
|
||||
"skip_automatically": "خودکار",
|
||||
"skip_segment": "گذر از بخش",
|
||||
"minimize_recommendations_default": "به طور پیش فرض پیشنهادها را حداقل کنید.",
|
||||
"min_segment_length": "حداقل طول بخش (به ثانیه)"
|
||||
},
|
||||
"titles": {
|
||||
"history": "سابقه",
|
||||
"history": "تاریخچه",
|
||||
"preferences": "تنظیمات",
|
||||
"feed": "خوراک",
|
||||
"register": "ثبت نام",
|
||||
"login": "ورود",
|
||||
"trending": "محبوب",
|
||||
"subscriptions": "اشتراکها"
|
||||
"subscriptions": "اشتراکها",
|
||||
"account": "حساب کاربری",
|
||||
"instance": "نمونه",
|
||||
"playlists": "لیست پخش",
|
||||
"player": "پخش کننده",
|
||||
"bookmarks": "نشاندارها",
|
||||
"livestreams": "پخش زنده",
|
||||
"channels": "کانالها",
|
||||
"channel_groups": "گروه های کانال"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "تماشا روی {0}"
|
||||
@ -86,7 +113,9 @@
|
||||
"instance_locations": "محل های سرویس",
|
||||
"has_cdn": "CDN دارد؟",
|
||||
"ssl_score": "امتیاز SSL",
|
||||
"instance_name": "نام سرویس"
|
||||
"instance_name": "نام سرویس",
|
||||
"version": "نسخه",
|
||||
"registered_users": "کاربران تایید شده"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "سنجاق شده توسط {author}"
|
||||
|
@ -101,7 +101,6 @@
|
||||
"show_watch_on_youtube": "Näytä Katso YouTubessa -painike",
|
||||
"different_auth_instance": "Käytä eri instanssia todennukseen",
|
||||
"download_as_txt": "Lataa .txt-tiedostona",
|
||||
"rename_playlist": "Nimeä soittolista uudelleen",
|
||||
"show_chapters": "Luvut",
|
||||
"minimize_comments": "Minimoi kommentit",
|
||||
"minimize_comments_default": "Minimoi kommentit oletusarvoisesti",
|
||||
@ -118,7 +117,6 @@
|
||||
"hide_watched": "Piilota katsotut videot syötteessä",
|
||||
"time_code": "Aikakoodi (sekunteina)",
|
||||
"follow_link": "Avaa linkki",
|
||||
"new_playlist_name": "Soittolistan uusi nimi",
|
||||
"invalidate_session": "Kirjaudu ulos kaikista laitteista",
|
||||
"logout": "Kirjaudu ulos tästä laitteesta",
|
||||
"backup_preferences": "Varmuuskopiointiasetukset",
|
||||
|
@ -12,7 +12,9 @@
|
||||
"instance": "Instance",
|
||||
"player": "Lecteur",
|
||||
"livestreams": "Diffusions en direct",
|
||||
"channels": "Chaînes"
|
||||
"channels": "Chaînes",
|
||||
"bookmarks": "Marque-pages",
|
||||
"channel_groups": "Groupes de chaînes"
|
||||
},
|
||||
"actions": {
|
||||
"subscribe": "S'abonner - {count}",
|
||||
@ -66,7 +68,7 @@
|
||||
"yes": "Oui",
|
||||
"loading": "Chargement…",
|
||||
"filter": "Filtrer",
|
||||
"search": "Rechercher",
|
||||
"search": "Rechercher (Ctrl+K)",
|
||||
"view_ssl_score": "Afficher le score SSL",
|
||||
"clear_history": "Effacer l'historique",
|
||||
"load_more_replies": "Charger plus de réponses",
|
||||
@ -102,8 +104,6 @@
|
||||
"piped_link": "Lien vers Piped",
|
||||
"follow_link": "Ouvrir le lien",
|
||||
"time_code": "Horodatage (en secondes)",
|
||||
"rename_playlist": "Renommer la liste de lecture",
|
||||
"new_playlist_name": "Nouveau nom de la liste de lecture",
|
||||
"show_chapters": "Chapitres",
|
||||
"store_search_history": "Mémoriser l'historique de recherche",
|
||||
"documentation": "Documentation",
|
||||
@ -116,7 +116,27 @@
|
||||
"minimize_comments": "Minimiser les commentaires",
|
||||
"show_watch_on_youtube": "Afficher le bouton Regarder sur YouTube",
|
||||
"minimize_chapters_default": "Minimiser les chapitres par défaut",
|
||||
"no_valid_playlists": "Le fichier ne contient pas de listes de lecture valides !"
|
||||
"no_valid_playlists": "Le fichier ne contient pas de listes de lecture valides !",
|
||||
"bookmark_playlist": "Marque-page",
|
||||
"playlist_bookmarked": "Dans les marque-pages",
|
||||
"with_playlist": "Partager avec la liste de lecture",
|
||||
"skip_button_only": "Afficher le bouton de saut",
|
||||
"skip_automatically": "Automatiquement",
|
||||
"min_segment_length": "Longueur minimale du segment (en secondes)",
|
||||
"skip_segment": "Sauter le segment",
|
||||
"show_less": "Afficher moins",
|
||||
"okay": "OK",
|
||||
"edit_playlist": "Éditer la liste de lecture",
|
||||
"playlist_name": "Nom de la liste de lecture",
|
||||
"auto_display_captions": "Afficher sous-titres automatiquement",
|
||||
"dismiss": "Rejeter",
|
||||
"cancel": "Annuler",
|
||||
"playlist_description": "Description de la liste de lecture",
|
||||
"create_group": "Créer un groupe",
|
||||
"group_name": "Nom du groupe",
|
||||
"autoplay_next_countdown": "Temps par défaut avant la prochaine vidéo (en secondes)",
|
||||
"chapters_layout_mobile": "Format des chapitres sur mobile",
|
||||
"show_search_suggestions": "Afficher les suggestions de recherche"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Regarder sur {0}"
|
||||
@ -129,7 +149,11 @@
|
||||
"ratings_disabled": "Évaluations désactivées",
|
||||
"chapters": "Chapitres",
|
||||
"live": "{0} en direct",
|
||||
"shorts": "Courtes"
|
||||
"shorts": "Courtes",
|
||||
"all": "Tout",
|
||||
"category": "Catégorie",
|
||||
"chapters_horizontal": "Horizontal",
|
||||
"chapters_vertical": "Vertical"
|
||||
},
|
||||
"preferences": {
|
||||
"ssl_score": "Score SSL",
|
||||
@ -172,6 +196,8 @@
|
||||
"page_not_found": "Page non trouvée",
|
||||
"copied": "Copié !",
|
||||
"cannot_copy": "Impossible de copier !",
|
||||
"local_storage": "Cette action nécessite localStorage, les cookies sont-ils activés ?"
|
||||
"local_storage": "Cette action nécessite localStorage, les cookies sont-ils activés ?",
|
||||
"register_no_email_note": "Il n'est pas recommandé d'utiliser une adresse courriel omme nom d'utilisateur. Continuer quand même ?",
|
||||
"next_video_countdown": "Lecture de la prochaine vidéo dans {0}s"
|
||||
}
|
||||
}
|
||||
|
47
src/locales/gl.json
Normal file
47
src/locales/gl.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"titles": {
|
||||
"register": "Crear conta",
|
||||
"feed": "Cronoloxía",
|
||||
"preferences": "Preferencias",
|
||||
"history": "Historial",
|
||||
"trending": "En voga",
|
||||
"account": "Conta",
|
||||
"player": "Reprodutor",
|
||||
"login": "Acceder",
|
||||
"instance": "Instancia",
|
||||
"bookmarks": "Marcadores",
|
||||
"subscriptions": "Subscricións",
|
||||
"playlists": "Listas",
|
||||
"livestreams": "En directo",
|
||||
"channels": "Canles",
|
||||
"channel_groups": "Grupos de canles"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Ver en {0}",
|
||||
"failed": "Fallou con código do erro {0}, mira o rexistro para máis info"
|
||||
},
|
||||
"actions": {
|
||||
"subscribe": "Subscribirse - {count}",
|
||||
"sort_by": "Orde por:",
|
||||
"least_recent": "Máis antigo",
|
||||
"most_recent": "Máis recente",
|
||||
"channel_name_asc": "Nome da canle (A-Z)",
|
||||
"unsubscribe": "Retirar subscrición - {count}",
|
||||
"view_subscriptions": "Ver Subscricións",
|
||||
"back": "Volver",
|
||||
"uses_api_from": "Usa a API desde ",
|
||||
"enable_sponsorblock": "Activar Sponsoblock",
|
||||
"skip_button_only": "Mostrar botón omitir",
|
||||
"skip_automatically": "Automáticamente",
|
||||
"channel_name_desc": "Nome da canle (Z-A)",
|
||||
"skip_sponsors": "Omitir Sponsors",
|
||||
"show_markers": "Mostrar Marcadores no Reprodutor",
|
||||
"skip_segment": "Omitir Segmento",
|
||||
"dark": "Escuro",
|
||||
"min_segment_length": "Lonxitude mínima do segmento (en segundos)",
|
||||
"theme": "Decorado",
|
||||
"auto": "Auto",
|
||||
"light": "Claro",
|
||||
"autoplay_video": "Reprodución automática"
|
||||
}
|
||||
}
|
@ -12,10 +12,14 @@
|
||||
"playlists": "רשימות נגינה",
|
||||
"instance": "עותק",
|
||||
"livestreams": "שידורים חיים",
|
||||
"channels": "ערוצים"
|
||||
"channels": "ערוצים",
|
||||
"bookmarks": "סימניות",
|
||||
"channel_groups": "קבוצות ערוץ",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "לצפות ב־{0}"
|
||||
"watch_on": "לצפות ב־{0}",
|
||||
"failed": "חל כשל עם קוד שגיאה {0}, מידע נוסף ביומנים"
|
||||
},
|
||||
"actions": {
|
||||
"subscribe": "מינוי - {count}",
|
||||
@ -43,20 +47,20 @@
|
||||
"audio_only": "שמע בלבד",
|
||||
"default_quality": "איכות ברירת מחדל",
|
||||
"buffering_goal": "יעד שמירה למטמון (בשניות)",
|
||||
"country_selection": "בחירת מדינה",
|
||||
"country_selection": "מדינה",
|
||||
"default_homepage": "עמוד הבית כברירת מחדל",
|
||||
"show_comments": "הצגת תגובות",
|
||||
"minimize_description_default": "מזעור התגובות כברירת מחדל",
|
||||
"store_watch_history": "שחזור היסטוריית הצפייה",
|
||||
"language_selection": "בחירת שפה",
|
||||
"language_selection": "שפה",
|
||||
"instances_list": "רשימת עותקים",
|
||||
"enabled_codecs": "מפענחים פעילים (מגוון)",
|
||||
"instance_selection": "בחירת עותק",
|
||||
"show_more": "להציג עוד",
|
||||
"instance_selection": "עותק",
|
||||
"show_more": "להציג יותר",
|
||||
"yes": "כן",
|
||||
"no": "לא",
|
||||
"export_to_json": "ייצוא ל־JSON",
|
||||
"import_from_json": "ייבוא מ־JSON/CSV",
|
||||
"import_from_json": "ייבוא מ־JSON",
|
||||
"show_markers": "הצגת סמנים בנגן",
|
||||
"auto_play_next_video": "לנגן את הסרטון הבא אוטומטית",
|
||||
"donations": "תרומות בפיתוח",
|
||||
@ -77,7 +81,7 @@
|
||||
"logout": "יציאה מהחשבון במכשיר הזה",
|
||||
"minimize_recommendations_default": "מזעור המלצות כברירת מחדל",
|
||||
"invalidate_session": "להוציא את כל המכשירים מהחשבון",
|
||||
"instance_auth_selection": "בחירת עותק אימות",
|
||||
"instance_auth_selection": "עותק אימות",
|
||||
"clone_playlist": "שכפול רשימת נגינה",
|
||||
"clone_playlist_success": "שוכפל בהצלחה!",
|
||||
"download_as_txt": "הורדה כ־.txt",
|
||||
@ -99,11 +103,9 @@
|
||||
"disable_lbry": "השבתת הזרמה עם LBRY",
|
||||
"enable_lbry_proxy": "הפעלת מתווך ל־LBRY",
|
||||
"view_ssl_score": "הצגת דירוג SSL",
|
||||
"search": "חיפוש",
|
||||
"search": "חיפוש (Ctrl+K)",
|
||||
"loop_this_video": "ניגון הסרטון בלולאה",
|
||||
"minimize_recommendations": "מזעור המלצות",
|
||||
"rename_playlist": "שינוי שם רשימת נגינה",
|
||||
"new_playlist_name": "שם לרשימת נגינה חדשה",
|
||||
"show_chapters": "פרקים",
|
||||
"skip_intro": "דילוג על הפוגה/הנפשת הקדמה",
|
||||
"skip_outro": "דילוג על כרטיסי סיום/קרדיטים",
|
||||
@ -120,7 +122,31 @@
|
||||
"minimize_chapters_default": "מזעור הפרקים כברירת מחדל",
|
||||
"show_watch_on_youtube": "הצגת כפתור לצפייה ב־YouTube",
|
||||
"no_valid_playlists": "הקובץ לא מכיל רשימות נגינה תקפות!",
|
||||
"with_playlist": "שיתוף עם רשימת נגינה"
|
||||
"with_playlist": "שיתוף עם רשימת נגינה",
|
||||
"playlist_bookmarked": "נוסף לסימניות",
|
||||
"bookmark_playlist": "סימנייה",
|
||||
"skip_button_only": "הצגת כפתור דילוג",
|
||||
"min_segment_length": "אורך מקטע מזערי (בשניות)",
|
||||
"skip_segment": "דילוג על מקטע",
|
||||
"skip_automatically": "אוטומטית",
|
||||
"show_less": "להציג פחות",
|
||||
"autoplay_next_countdown": "ספירה לאחור כברירת מחדל עד לסרטון הבא (בשניות)",
|
||||
"dismiss": "התעלמות",
|
||||
"create_group": "יצירת קבוצה",
|
||||
"group_name": "שם הקבוצה",
|
||||
"auto_display_captions": "הצגת כתוביות אוטומטית",
|
||||
"cancel": "ביטול",
|
||||
"edit_playlist": "עריכת רשימת נגינה",
|
||||
"playlist_name": "שם רשימת הנגינה",
|
||||
"playlist_description": "תיאור רשימת הנגינה",
|
||||
"okay": "אישור",
|
||||
"show_search_suggestions": "הצגת הצעות חיפוש",
|
||||
"chapters_layout_mobile": "פריסת פרקים בנייד",
|
||||
"delete_automatically": "למחוק אוטומטית לאחר",
|
||||
"enable_dearrow": "הפעלת DeArrow",
|
||||
"generate_qrcode": "יצירת קוד QR",
|
||||
"import_from_json_csv": "ייבוא מ־JSON/CSV",
|
||||
"download_frame": "הורדת תמונית"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "ננעץ על ידי {author}",
|
||||
@ -139,7 +165,9 @@
|
||||
},
|
||||
"login": {
|
||||
"username": "שם משתמש",
|
||||
"password": "סיסמה"
|
||||
"password": "סיסמה",
|
||||
"password_confirm": "אישור סיסמה",
|
||||
"passwords_incorrect": "הסיסמאות שונות זו מזו!"
|
||||
},
|
||||
"video": {
|
||||
"videos": "סרטונים",
|
||||
@ -149,7 +177,13 @@
|
||||
"ratings_disabled": "הדירוגים מושבתים",
|
||||
"chapters": "פרקים",
|
||||
"live": "{0} בשידור חי",
|
||||
"shorts": "קצרצרים"
|
||||
"shorts": "קצרצרים",
|
||||
"all": "הכול",
|
||||
"category": "קטגוריה",
|
||||
"chapters_horizontal": "אופקית",
|
||||
"chapters_vertical": "אנכית",
|
||||
"visibility": "חשיפה",
|
||||
"license": "רישיון"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "האם התכוונת לביטוי {0}?",
|
||||
@ -160,14 +194,21 @@
|
||||
"music_songs": "YT Music: שירים",
|
||||
"music_videos": "YT Music: סרטונים",
|
||||
"music_albums": "YT Music: אלבומים",
|
||||
"music_playlists": "YT Music: רשימות נגינה"
|
||||
"music_playlists": "YT Music: רשימות נגינה",
|
||||
"music_artists": "YT Music: אומנים"
|
||||
},
|
||||
"info": {
|
||||
"preferences_note": "לתשומת לבך: ההעדפות נשמרות באחסון המקומי של הדפדפן שלך. מחיקת נתוני הדפדפן שלך תאפס אותם.",
|
||||
"page_not_found": "העמוד לא נמצא",
|
||||
"copied": "הועתק!",
|
||||
"cannot_copy": "לא ניתן להעתיק!",
|
||||
"local_storage": "פעולה זו דורשת אחסון מקומי (localStorage), האם עוגיות פעילות?"
|
||||
"local_storage": "פעולה זו דורשת אחסון מקומי (localStorage), האם עוגיות פעילות?",
|
||||
"register_no_email_note": "לא מומלץ להשתמש בכתובת דוא״ל כשם משתמש. להמשיך בכל זאת?",
|
||||
"next_video_countdown": "הסרטון הבא יתנגן בעוד {0} שניות",
|
||||
"days": "{amount} ימים",
|
||||
"weeks": "{amount} שבועות",
|
||||
"months": "{amount} חודשים",
|
||||
"hours": "{amount} שעות"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "נרשמת אל: {0}"
|
||||
|
@ -9,7 +9,10 @@
|
||||
"feed": "फ़ीड",
|
||||
"playlists": "प्लेलिस्ट",
|
||||
"livestreams": "लाइव स्ट्रीम",
|
||||
"channels": "चैनल"
|
||||
"channels": "चैनल",
|
||||
"player": "चालक",
|
||||
"account": "खाता",
|
||||
"instance": "इंस्टैंस"
|
||||
},
|
||||
"actions": {
|
||||
"subscribe": "सदस्यता लें - {count}",
|
||||
@ -17,7 +20,7 @@
|
||||
"unsubscribe": "सदस्यता ले ली है - {count}",
|
||||
"no": "नहीं",
|
||||
"hide_replies": "जवाब छिपाएं",
|
||||
"search": "खोजें",
|
||||
"search": "खोजें (Ctrl+K)",
|
||||
"loop_this_video": "इस वीडियो को लूप करें",
|
||||
"loading": "लोड हो रहा है...",
|
||||
"show_description": "विवरण दिखाएं",
|
||||
@ -38,17 +41,17 @@
|
||||
"autoplay_video": "ऑटोप्ले वीडियो",
|
||||
"audio_only": "सिर्फ़ ध्वनि",
|
||||
"default_quality": "डिफ़ॉल्ट गुणवत्ता",
|
||||
"country_selection": "देश चयन",
|
||||
"country_selection": "देश",
|
||||
"show_comments": "टिप्पणियाँ दिखाएँ",
|
||||
"store_watch_history": "स्टोर देखने का इतिहास",
|
||||
"language_selection": "भाषा चयन",
|
||||
"language_selection": "भाषा",
|
||||
"instances_list": "इंस्टेंस सूची",
|
||||
"instance_selection": "इंस्टेंस चयन",
|
||||
"instance_selection": "इंस्टेंस",
|
||||
"show_more": "और दिखाओ",
|
||||
"export_to_json": "JSON में निर्यात करें",
|
||||
"import_from_json": "JSON/CSV से आयात करें",
|
||||
"auto_play_next_video": "अगला वीडियो ऑटोप्ले करें",
|
||||
"donations": "दान",
|
||||
"donations": "विकास दान",
|
||||
"minimize_recommendations": "सिफारिशों को कम करें",
|
||||
"show_recommendations": "सिफारिशें दिखाएं",
|
||||
"disable_lbry": "स्ट्रीमिंग के लिए LBRY अक्षम करें",
|
||||
@ -59,19 +62,24 @@
|
||||
"load_more_replies": "और जवाब लोड करें",
|
||||
"enabled_codecs": "सक्षम कोडेक्स (एकाधिक)",
|
||||
"buffering_goal": "बफरिंग गोल (सेकंड में)",
|
||||
"delete_playlist_confirm": "क्या आप वाकई इस प्लेलिस्ट को हटाना चाहते हैं?",
|
||||
"delete_playlist_confirm": "प्लेलिस्ट को मिटाना है?",
|
||||
"add_to_playlist": "प्लेलिस्ट में जोड़ें",
|
||||
"remove_from_playlist": "प्लेलिस्ट से निकाले",
|
||||
"delete_playlist_video_confirm": "क्या आप वाकई इस प्लेलिस्ट से इस वीडियो को निकालना चाहेंगे?",
|
||||
"delete_playlist_video_confirm": "वीडियो को प्लेलिस्ट से निकालना है?",
|
||||
"create_playlist": "प्लेलिस्ट बनायें",
|
||||
"select_playlist": "एक प्लेलिस्ट चुनें",
|
||||
"please_select_playlist": "कृपया एक प्लेलिस्ट चुनें",
|
||||
"delete_playlist": "प्लेलिस्ट हटाएं"
|
||||
"delete_playlist": "प्लेलिस्ट हटाएं",
|
||||
"enable_sponsorblock": "विज्ञापन प्रतिबंध करें",
|
||||
"default_homepage": "स्वतः निर्धारित मुख्यपृष्ठ",
|
||||
"sort_by": "वर्गीकरण:",
|
||||
"skip_automatically": "स्वतः",
|
||||
"delete_account": "खाता मिटाएँ"
|
||||
},
|
||||
"video": {
|
||||
"views": "{views} बार देखा गया",
|
||||
"videos": "वीडियो",
|
||||
"watched": "पहले ही देखा",
|
||||
"watched": "पहले ही देखा हुआ",
|
||||
"ratings_disabled": "रेटिंग अक्षम",
|
||||
"chapters": "चैप्टर",
|
||||
"live": "{0} लाइव"
|
||||
|
@ -4,10 +4,16 @@
|
||||
"watched": "Gledano",
|
||||
"views": "{views} gledanja",
|
||||
"videos": "Videa",
|
||||
"ratings_disabled": "Ocjenjivanje isključeno",
|
||||
"ratings_disabled": "Ocjene su isključene",
|
||||
"chapters": "Poglavlja",
|
||||
"live": "{0} uživo",
|
||||
"shorts": "Kratka videa"
|
||||
"shorts": "Kratka videa",
|
||||
"all": "Sva",
|
||||
"category": "Kategorija",
|
||||
"chapters_horizontal": "Vodoravno",
|
||||
"chapters_vertical": "Okomito",
|
||||
"license": "Licenca",
|
||||
"visibility": "Vidljivost"
|
||||
},
|
||||
"preferences": {
|
||||
"ssl_score": "SSL ocjena",
|
||||
@ -20,13 +26,13 @@
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Prikvačio korisnik {author}",
|
||||
"disabled": "Prijenosnik onemogućuje komentare.",
|
||||
"disabled": "Prijenosnik je isključio komentare.",
|
||||
"loading": "Učitavanje komentara...",
|
||||
"user_disabled": "Komentari su isključeni u postavkama."
|
||||
},
|
||||
"actions": {
|
||||
"enable_lbry_proxy": "Uključi proxy za LBRY",
|
||||
"disable_lbry": "Onemogući LBRY za prijenos",
|
||||
"disable_lbry": "Isključi LBRY za prijenos",
|
||||
"minimize_description_default": "Standardno sakrij opis",
|
||||
"minimize_description": "Sakrij opis",
|
||||
"show_description": "Prikaži opis",
|
||||
@ -40,14 +46,14 @@
|
||||
"no": "Ne",
|
||||
"yes": "Da",
|
||||
"show_more": "Prikaži više",
|
||||
"instance_selection": "Izbor instance",
|
||||
"enabled_codecs": "Uključeni kodeki (višestruki)",
|
||||
"instance_selection": "Instanca",
|
||||
"enabled_codecs": "Uključeni kodeki (moguće je odabrati nekoliko kodeka)",
|
||||
"instances_list": "Popis instanci",
|
||||
"language_selection": "Izbor jezika",
|
||||
"language_selection": "Jezik",
|
||||
"store_watch_history": "Spremi povijest gledanja",
|
||||
"show_comments": "Prikaži komentare",
|
||||
"default_homepage": "Standardna početna stranica",
|
||||
"country_selection": "Izbor zemlje",
|
||||
"country_selection": "Zemlja",
|
||||
"buffering_goal": "Cilj međuspremnika (u sekundama)",
|
||||
"default_quality": "Standardna kvaliteta",
|
||||
"audio_only": "Samo zvuk",
|
||||
@ -69,36 +75,36 @@
|
||||
"view_subscriptions": "Pogledaj pretplate",
|
||||
"unsubscribe": "Otkaži pretplatu – {count}",
|
||||
"subscribe": "Pretplati se – {count}",
|
||||
"skip_interaction": "Preskoči podsjetnik za interakciju (zahtijeva pretplatu)",
|
||||
"skip_interaction": "Preskoči podsjetnik za interakciju (pretplata)",
|
||||
"skip_outro": "Preskoči odjavnu špicu",
|
||||
"skip_intro": "Preskoči pauzu i uvodnu animaciju",
|
||||
"skip_sponsors": "Preskoči sponzore",
|
||||
"enable_sponsorblock": "Uključi blok sponsora",
|
||||
"loading": "Učitavanje…",
|
||||
"filter": "Filtar",
|
||||
"search": "Pretraga",
|
||||
"search": "Pretraga (Ctrl+K)",
|
||||
"view_ssl_score": "Pogledaj SSL ocjenu",
|
||||
"hide_replies": "Sakrij odgovore",
|
||||
"load_more_replies": "Prikaži više odgovora",
|
||||
"clear_history": "Obriši povijest",
|
||||
"skip_highlight": "Preskoči isticanje",
|
||||
"skip_filler_tangent": "Preskoči nebitne međudijelove",
|
||||
"delete_playlist_confirm": "Izbrisati ovaj popis snimaka?",
|
||||
"remove_from_playlist": "Ukloni iz popisa snimaka",
|
||||
"create_playlist": "Stvori popis snimaka",
|
||||
"delete_playlist": "Izbriši popis snimaka",
|
||||
"add_to_playlist": "Dodaj u popis snimaka",
|
||||
"select_playlist": "Odaberi popis snimaka",
|
||||
"please_select_playlist": "Odaberi popis snimaka",
|
||||
"delete_playlist_video_confirm": "Ukloniti video iz popisa snimaka?",
|
||||
"show_markers": "Prikaži oznake na Pokretaču",
|
||||
"skip_filler_tangent": "Preskoči prazne umetke",
|
||||
"delete_playlist_confirm": "Izbrisati ovu playlistu?",
|
||||
"remove_from_playlist": "Ukloni iz playliste",
|
||||
"create_playlist": "Stvori playlistu",
|
||||
"delete_playlist": "Izbriši playlistu",
|
||||
"add_to_playlist": "Dodaj u playlistu",
|
||||
"select_playlist": "Odaberi playlistu",
|
||||
"please_select_playlist": "Odaberi playlistu",
|
||||
"delete_playlist_video_confirm": "Ukloniti video iz playliste?",
|
||||
"show_markers": "Prikaži oznake na playeru",
|
||||
"delete_account": "Izbriši račun",
|
||||
"logout": "Odjavi se s ovog uređaja",
|
||||
"minimize_recommendations_default": "Standardno sakrij preporuke",
|
||||
"invalidate_session": "Odjavi sve uređaje",
|
||||
"different_auth_instance": "Koristi drugu instancu za autentifikaciju",
|
||||
"instance_auth_selection": "Odabir instance autentifikacije",
|
||||
"clone_playlist": "Dupliciraj popis snimaka",
|
||||
"instance_auth_selection": "Instanca autentifikacije",
|
||||
"clone_playlist": "Dupliciraj playlistu",
|
||||
"clone_playlist_success": "Dupliciranje uspjelo!",
|
||||
"download_as_txt": "Preuzmi kao .txt",
|
||||
"reset_preferences": "Resetiraj postavke",
|
||||
@ -111,14 +117,12 @@
|
||||
"confirm_reset_preferences": "Stvarno želiš resetirati tvoje postavke?",
|
||||
"backup_preferences": "Spremi sigurnosnu kopiju postavki",
|
||||
"with_timecode": "Dijeli s vremenskim kodom",
|
||||
"rename_playlist": "Preimenuj popis snimaka",
|
||||
"new_playlist_name": "Ime novog popisa snimaka",
|
||||
"share": "Dijeli",
|
||||
"show_chapters": "Poglavlja",
|
||||
"documentation": "Dokumentacija",
|
||||
"source_code": "Izvorni kod",
|
||||
"instance_donations": "Donacije instance",
|
||||
"store_search_history": "Spremi povijest pretrage",
|
||||
"store_search_history": "Povijest pretrage trgovine",
|
||||
"hide_watched": "Sakrij gledana videa u novostima",
|
||||
"status_page": "Stanje",
|
||||
"reply_count": "{count} odgovora",
|
||||
@ -126,8 +130,30 @@
|
||||
"minimize_comments": "Sakrij komentare",
|
||||
"show_watch_on_youtube": "Prikaži gumb „Gledaj na YouTubeu”",
|
||||
"minimize_chapters_default": "Standardno sakrij poglavlja",
|
||||
"no_valid_playlists": "Datoteka ne sadrži ispravne popise snimaka!",
|
||||
"with_playlist": "Dijeli s popisom snimaka"
|
||||
"no_valid_playlists": "Datoteka ne sadrži ispravne playliste!",
|
||||
"with_playlist": "Dijeli s playlistom",
|
||||
"playlist_bookmarked": "Zabilježeno",
|
||||
"bookmark_playlist": "Zabilježi",
|
||||
"skip_button_only": "Prikaži gumb za preskakanje",
|
||||
"skip_automatically": "Automatski",
|
||||
"skip_segment": "Preskoči segment",
|
||||
"min_segment_length": "Najmanja duljina segmenta (u sekundama)",
|
||||
"show_less": "Prikaži manje",
|
||||
"autoplay_next_countdown": "Standardno odbrojavanje do sljedećeg videa (u sekundama)",
|
||||
"dismiss": "Odbaci",
|
||||
"create_group": "Stvori grupu",
|
||||
"group_name": "Ime grupe",
|
||||
"auto_display_captions": "Automatski prikaži titlove",
|
||||
"cancel": "Odustani",
|
||||
"okay": "U redu",
|
||||
"edit_playlist": "Uredi playlistu",
|
||||
"playlist_name": "Ime playliste",
|
||||
"playlist_description": "Opis playliste",
|
||||
"chapters_layout_mobile": "Raspored poglavlja na mobilnim uređajima",
|
||||
"show_search_suggestions": "Prikaži prijedloge pretrage",
|
||||
"delete_automatically": "Automatski izbriši nakon",
|
||||
"enable_dearrow": "Aktiviraj DeArrow",
|
||||
"generate_qrcode": "Generiraj QR kod"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Gledaj na {0}"
|
||||
@ -140,30 +166,36 @@
|
||||
"register": "Registracija",
|
||||
"login": "Prijava",
|
||||
"trending": "U trendu",
|
||||
"playlists": "Popisi snimaka",
|
||||
"playlists": "Playliste",
|
||||
"account": "Račun",
|
||||
"instance": "Instanca",
|
||||
"player": "Pokretač",
|
||||
"player": "Player",
|
||||
"channels": "Kanali",
|
||||
"livestreams": "Prijenosi uživo"
|
||||
"livestreams": "Prijenosi uživo",
|
||||
"bookmarks": "Zabilješke",
|
||||
"channel_groups": "Grupe kanala",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"login": {
|
||||
"password": "Lozinka",
|
||||
"username": "Korisničko ime"
|
||||
"username": "Korisničko ime",
|
||||
"password_confirm": "Potvrdi lozinku",
|
||||
"passwords_incorrect": "Lozinke se ne poklapaju!"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Misliš li: {0}?",
|
||||
"all": "YouTube: Sve",
|
||||
"videos": "YouTube: Videa",
|
||||
"channels": "YouTube: Kanali",
|
||||
"playlists": "YouTube: Popisi snimaka",
|
||||
"playlists": "YouTube: Playliste",
|
||||
"music_songs": "YT Music: Pjesme",
|
||||
"music_videos": "YT Music: Videa",
|
||||
"music_albums": "YT Music: Albumi",
|
||||
"music_playlists": "YT Music: Popisi snimaka"
|
||||
"music_playlists": "YT Music: Playliste",
|
||||
"music_artists": "YT Music: Izvođači"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Pretplata na: {0}"
|
||||
"subscribed_channels_count": "Broj pretplata: {0}"
|
||||
},
|
||||
"information": {
|
||||
"preferences_note": "Napomena: postavke se spremaju u lokalno spremište preglednika. Brisanje podataka preglednika resetira postavke."
|
||||
@ -173,6 +205,12 @@
|
||||
"page_not_found": "Stranica nije pronađena",
|
||||
"copied": "Kopirano!",
|
||||
"cannot_copy": "Nije moguće kopirati!",
|
||||
"local_storage": "Ova radnja zahtijeva lokalno spremište. Jesu li kolačići uključeni?"
|
||||
"local_storage": "Ova radnja zahtijeva lokalno spremište. Jesu li kolačići uključeni?",
|
||||
"register_no_email_note": "Korištenje e-mail adrese kao korisničkog imena se ne preporučuje. Svejedno nastaviti?",
|
||||
"next_video_countdown": "Reprodukcija sljedećeg videa za {0} s",
|
||||
"hours": "{amount} h",
|
||||
"days": "{amount} dan(a)",
|
||||
"weeks": "{amount} tj",
|
||||
"months": "{amount} mj"
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,11 @@
|
||||
"subscriptions": "Feliratkozások",
|
||||
"playlists": "Lejátszási listák",
|
||||
"trending": "Felkapott",
|
||||
"account": "Fiók"
|
||||
"account": "Fiók",
|
||||
"player": "Lejátszó",
|
||||
"instance": "Szerver",
|
||||
"livestreams": "Élő adások",
|
||||
"channels": "Csatornák"
|
||||
},
|
||||
"actions": {
|
||||
"subscribe": "Feliratkozás - {count}",
|
||||
@ -51,7 +55,7 @@
|
||||
"instance_selection": "Példány kiválasztása",
|
||||
"skip_filler_tangent": "Témától eltérő töltelék/viccek",
|
||||
"loop_this_video": "Videó ismétlése",
|
||||
"donations": "Támogatások",
|
||||
"donations": "Fejlesztési támogatások",
|
||||
"minimize_description": "Leírás minimalizálása",
|
||||
"show_recommendations": "Javaslatok megjelenítése",
|
||||
"enable_lbry_proxy": "Proxy engedélyezése a LBRY számára",
|
||||
@ -85,7 +89,33 @@
|
||||
"different_auth_instance": "Másik példány használata a hitelesítéshez",
|
||||
"instance_auth_selection": "Autentikációs példány kiválasztása",
|
||||
"clone_playlist": "Lejátszási lista klónozása",
|
||||
"clone_playlist_success": "Sikeresen klónozva!"
|
||||
"clone_playlist_success": "Sikeresen klónozva!",
|
||||
"reset_preferences": "Alaphelyzetbe állítás",
|
||||
"restore_preferences": "Beállítások betöltése fájlból",
|
||||
"instance_donations": "Szerver adományozások",
|
||||
"piped_link": "Piped link",
|
||||
"time_code": "Idő kód (másodpercekben)",
|
||||
"show_chapters": "Fejezetek",
|
||||
"download_as_txt": "Letöltés szövegdokumentumként",
|
||||
"source_code": "A szoftver kódja",
|
||||
"reply_count": "{count} hozzászólások",
|
||||
"documentation": "Dokumentáció",
|
||||
"minimize_chapters_default": "Mindig tüntesd el a fejezeteket",
|
||||
"hide_watched": "Ne mutassa a látott videókat a felíratkozásoknál",
|
||||
"show_watch_on_youtube": "Mutasd a \"Lejátszás Youtube-on\" gombot",
|
||||
"confirm_reset_preferences": "Biztos alaphelyzetbe állítod?",
|
||||
"backup_preferences": "Beállítások mentése",
|
||||
"share": "Megosztás",
|
||||
"with_timecode": "Megosztás & videó kezdés ettől a ponttól",
|
||||
"store_search_history": "Mentse a keresési előzményeket",
|
||||
"follow_link": "Követések link",
|
||||
"copy_link": "Link másolása",
|
||||
"status_page": "Státusz",
|
||||
"no_valid_playlists": "Nincs a fájlban egy valós lejátszási lista se!",
|
||||
"with_playlist": "Megosztás lejátszási listával",
|
||||
"minimize_comments_default": "Mindig tüntesd el a kommenteket",
|
||||
"minimize_comments": "Kommentek eltüntetése",
|
||||
"back_to_home": "Vissza a főoldalra"
|
||||
},
|
||||
"video": {
|
||||
"ratings_disabled": "Értékelések Letiltva",
|
||||
@ -129,5 +159,15 @@
|
||||
"disabled": "A hozzászólásokat a feltöltő letiltotta.",
|
||||
"user_disabled": "A beállításoknál a megjegyzések le vannak tiltva.",
|
||||
"loading": "Kommentek betöltése..."
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Feliratkozva: {0} csatornára"
|
||||
},
|
||||
"info": {
|
||||
"preferences_note": "Figyelem: A beállításaid a böngésződ tárhelyére vannak mentve. Ha törlöd őket el fognak tűnni a beállításaid.",
|
||||
"copied": "Másolva!",
|
||||
"local_storage": "Ennek a beállításnak szüksége van a \"lokális tárhely\" funkcióra, be vannak a sütik kapcsolva?",
|
||||
"cannot_copy": "Nem lehet másolni!",
|
||||
"page_not_found": "Oldnal nem található"
|
||||
}
|
||||
}
|
||||
|
190
src/locales/hy.json
Normal file
190
src/locales/hy.json
Normal file
@ -0,0 +1,190 @@
|
||||
{
|
||||
"actions": {
|
||||
"skip_automatically": "Ավտոմատվաց",
|
||||
"subscribe": "Բաժանորդ - {count}",
|
||||
"uses_api_from": "Օգտագործում է API -ից ",
|
||||
"enable_sponsorblock": "Միացնել հովանավորների արգելափակումը",
|
||||
"skip_intro": "Բաց թողնել ընդմիջում/ներածական անիմացիա",
|
||||
"skip_outro": "Բաց թողնել վերջնական քարտերը/վարկերը",
|
||||
"skip_preview": "Բաց թողնել նախադիտումը/վերանայումը",
|
||||
"skip_interaction": "Բաց թողնել փոխազդեցության հիշեցումը (բաժանորդագրվել)",
|
||||
"skip_self_promo": "Բաց թողնել չվճարված/ինքնագովազդ",
|
||||
"skip_highlight": "Բաց թողնել ընդգծումը",
|
||||
"skip_filler_tangent": "Բաց թողնել ավելորդ շոշափող",
|
||||
"show_markers": "Ցույց տալ մարկերները նվագարկչի վրա",
|
||||
"skip_segment": "Բաց թողնել հատվածը",
|
||||
"theme": "Թեմա",
|
||||
"auto": "Ավտոմատ",
|
||||
"dark": "Մութ",
|
||||
"audio_only": "Միայն աուդիո",
|
||||
"buffering_goal": "Բուֆերային նպատակ (վայրկյաններով)",
|
||||
"country_selection": "Երկրի ընտրություն",
|
||||
"default_homepage": "Կանխադրված գլխավոր էջ",
|
||||
"minimize_comments_default": "Նվազացնել մեկնաբանությունները",
|
||||
"channel_name_asc": "Ալիքի անունը (A-Z)",
|
||||
"unsubscribe": "Չեղարկել",
|
||||
"view_subscriptions": "Դիտել բաժանորդագրությունները",
|
||||
"least_recent": "Նվազագույնը վերջին",
|
||||
"sort_by": "Դասավորել ըստ:",
|
||||
"most_recent": "Ամենավերջին",
|
||||
"back": "Ետ",
|
||||
"channel_name_desc": "Ալիքի անունը (Z-A)",
|
||||
"autoplay_video": "Տեսանյութի ավտոմատ նվագարկում",
|
||||
"autoplay_next_countdown": "Կանխադրված հետհաշվարկ մինչև հաջորդ տեսանյութը (վայրկյանների ընթացքում)",
|
||||
"skip_button_only": "Ցույց տալ բաց թողնել կոճակը",
|
||||
"skip_sponsors": "Բաց թողնել հովանավորներին",
|
||||
"min_segment_length": "Սեգմենտի նվազագույն երկարությունը (վայրկյաններով)",
|
||||
"skip_non_music": "Բաց թողնել երաժշտությունը. ոչ երաժշտական բաժին",
|
||||
"default_quality": "Կանխադրված որակ",
|
||||
"light": "Լույս",
|
||||
"store_watch_history": "Խանութի դիտումների պատմությունը",
|
||||
"language_selection": "Լեզվի ընտրություն",
|
||||
"instances_list": "Դեպքերի ցուցակ",
|
||||
"minimize_description_default": "Նվազեցնել նկարագրությունը",
|
||||
"enabled_codecs": "Միացված կոդեկներ (բազմաթիվ)",
|
||||
"show_more": "Ցույց տալ ավելին",
|
||||
"yes": "Այո՛",
|
||||
"no": "Ոչ",
|
||||
"loop_this_video": "Կրկնել այս տեսանյութը",
|
||||
"auto_play_next_video": "Ավտոմատ նվագարկել հաջորդ տեսանյութը",
|
||||
"donations": "Զարգացման նվիրատվություններ",
|
||||
"show_comments": "Ցույց տալ մեկնաբանությունները",
|
||||
"minimize_description": "Նվազեգնել նկարագրությունը",
|
||||
"show_description": "Ցույց տալ նկարագրությունը",
|
||||
"show_recommendations": "Նվազեցնել առաջարկությունները",
|
||||
"disable_lbry": "Անջատել LBRY-ն եթերի համար",
|
||||
"enable_lbry_proxy": "Միացնել պռոքսի LBRY-ի համար",
|
||||
"view_ssl_score": "Դիտեք SSL միավորը",
|
||||
"search": "Որոնում (Ctrl+K)",
|
||||
"hide_replies": "Թաքցնել պատասխանները",
|
||||
"add_to_playlist": "Ավելացնել տեսացանկին",
|
||||
"remove_from_playlist": "Հեռացնել տեսացանկից",
|
||||
"delete_playlist_video_confirm": "Հեռացնե՞լ տեսանյութը տեսացանկից:",
|
||||
"create_playlist": "Ստեղծել տեսացանկ",
|
||||
"delete_playlist": "Ջնջել տեսացանկը",
|
||||
"delete_playlist_confirm": "Ջնջե՞լ այս տեսացանկը:",
|
||||
"please_select_playlist": "Խնդրում ենք ընտրել տեսացանկ",
|
||||
"delete_account": "Հաշիվը ջնջել",
|
||||
"logout": "Դուրս գալ այս սարքից",
|
||||
"minimize_chapters_default": "Նվազեցնել գլուխները",
|
||||
"show_watch_on_youtube": "Ցույց տալ <<դիտել YouTube-ում >> կոճակը",
|
||||
"invalidate_session": "Դուրս գալ բոլոր սարքերից",
|
||||
"instance_auth_selection": "Նույնականացման օրինակի ընտրություն",
|
||||
"clone_playlist_success": "Հաջողությամբ կլոնավորվեց:",
|
||||
"download_as_txt": "Ներբեռնեք որպես .txt",
|
||||
"reset_preferences": "Վերակայել նախապատվությունները",
|
||||
"confirm_reset_preferences": "Իսկապե՞ս ուզում եք վերակայել ձեր նախապատվությունները:",
|
||||
"backup_preferences": "Պահուստային նախապատվություններ",
|
||||
"restore_preferences": "Վերականգնել նախապատվությունները",
|
||||
"follow_link": "Հետևել հղմանը",
|
||||
"instance_donations": "Օրինակների նվիրատվություններ",
|
||||
"reply_count": "{count} պատասխան",
|
||||
"no_valid_playlists": "Ֆայլը վավեր տեսացանկկեր չի պարունակում:",
|
||||
"with_playlist": "Կիսվեք տեսացանկով",
|
||||
"bookmark_playlist": "Էջանիշ",
|
||||
"playlist_bookmarked": "Էջանշված",
|
||||
"show_less": "Ցույց տալ ավելի քիչ",
|
||||
"create_group": "Ստեղծել խումբ",
|
||||
"minimize_recommendations": "Նվազեցնել առաջարկությունները",
|
||||
"filter": "Զտել",
|
||||
"instance_selection": "Օրինակի ընտրություն",
|
||||
"import_from_json": "Ներմուծում JSON/CSV-ից",
|
||||
"export_to_json": "Արտահանել JSON",
|
||||
"minimize_comments": "Նվազագույնի հասցնել մեկնաբանությունները",
|
||||
"clear_history": "Մաքրել պատմություն",
|
||||
"loading": "Բեռնվում է...",
|
||||
"with_timecode": "Կիսվեք ժամանակի կոդով",
|
||||
"load_more_replies": "Բեռնել ավելի շատ պատասխաններ",
|
||||
"select_playlist": "Ընտրեք տեսացանկ",
|
||||
"minimize_recommendations_default": "Նվազեցնել առաջարկությունները",
|
||||
"clone_playlist": "Կլոնավորել տեսացանկը",
|
||||
"back_to_home": "Վերադարձ դեպի հիմնական էջ",
|
||||
"different_auth_instance": "Նույնականացման համար օգտագործեք այլ օրինակ",
|
||||
"share": "Կիսվել",
|
||||
"copy_link": "Պատճենել հղումը",
|
||||
"dismiss": "Հեռացնել",
|
||||
"piped_link": "Piped հղում",
|
||||
"time_code": "Ժամանակի կոդը (վայրկյաններով)",
|
||||
"store_search_history": "Խանութի որոնման պատմություն",
|
||||
"show_chapters": "Գլուխներ",
|
||||
"hide_watched": "Թաքցնել դիտված տեսանյութերը լրահոսում",
|
||||
"status_page": "Կարգավիճակ",
|
||||
"documentation": "Փաստաթղթեր",
|
||||
"source_code": "Աղբյուրի կոդը",
|
||||
"group_name": "Խմբի անվանումը"
|
||||
},
|
||||
"titles": {
|
||||
"trending": "Թրենդային",
|
||||
"login": "Մտնել",
|
||||
"register": "Գրանցվել",
|
||||
"feed": "Սկիզբ",
|
||||
"preferences": "Նախապատվություններ",
|
||||
"history": "Պատմություն",
|
||||
"subscriptions": "Հետևում եմ",
|
||||
"playlists": "Տեսացանկեր",
|
||||
"account": "Հաշիվ",
|
||||
"instance": "Օրինակ",
|
||||
"player": "նվագարկիչ",
|
||||
"livestreams": "Ուղիղ Եթերներ",
|
||||
"channels": "Ալիքներ",
|
||||
"bookmarks": "Էջանիշեր",
|
||||
"channel_groups": "Ալիքի խմբեր"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Դիտեք {0}-ով"
|
||||
},
|
||||
"preferences": {
|
||||
"registered_users": "Գրանցված օգտվողներ",
|
||||
"version": "Տարբերակ",
|
||||
"up_to_date": "Մինչ օրս",
|
||||
"ssl_score": "SSL միավոր",
|
||||
"instance_locations": "Օրինակների տեղադրություններ",
|
||||
"instance_name": "Օրինակի անվանումը",
|
||||
"has_cdn": "Ունի CDN:"
|
||||
},
|
||||
"login": {
|
||||
"username": "Օգտագործողի անունը",
|
||||
"password": "Գաղտնաբառ"
|
||||
},
|
||||
"video": {
|
||||
"videos": "Տեսանյութեր",
|
||||
"views": "{views} դիտում",
|
||||
"watched": "Դիտվաց",
|
||||
"sponsor_segments": "Հովանավորների հատվածներ",
|
||||
"ratings_disabled": "Վարկանիշներն անջատված են",
|
||||
"chapters": "Գլուխներ",
|
||||
"live": "{0} Եթեր",
|
||||
"shorts": "Shorts",
|
||||
"all": "Բոլորը",
|
||||
"category": "Կարգ"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Դուք նկատի ունեիք՝ {0}:",
|
||||
"all": "YouTube: Բոլորը",
|
||||
"videos": "YouTube: Տեսանյութեր",
|
||||
"channels": "YouTube: Ալիքներ",
|
||||
"playlists": "YouTube՝ տեսացանկ",
|
||||
"music_songs": "YT Երաժշտություն. երգեր",
|
||||
"music_videos": "YT Երաժշտություն. Տեսանյութեր",
|
||||
"music_albums": "YT Երաժշտություն. Ալբոմներ",
|
||||
"music_playlists": "YT Երաժշտություն. տեսացանկ"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Բաժանորդագրված է՝ {0}"
|
||||
},
|
||||
"comment": {
|
||||
"loading": "Մեկնաբանությունների բեռնում...",
|
||||
"pinned_by": "Ամրացված է {author}-ի կողմից",
|
||||
"disabled": "Մեկնաբանություններն անջատված են վերբեռնողի կողմից:",
|
||||
"user_disabled": "Մեկնաբանություններն անջատված են կարգավորումներում:"
|
||||
},
|
||||
"info": {
|
||||
"preferences_note": "Նշում. նախապատվությունները պահվում են ձեր բրաուզերի տեղական պահեստում: Ձեր բրաուզերի տվյալները ջնջելով դրանք կվերակայվեն:",
|
||||
"page_not_found": "Էջը չի գտնվել",
|
||||
"copied": "Պատճենվել է",
|
||||
"cannot_copy": "Հնարավոր չէ պատճենել:",
|
||||
"local_storage": "Այս գործողության համար պահանջվում է տեղական պահեստ, քուքի ֆայլերը միացվա՞ծ են:",
|
||||
"register_no_email_note": "Էլեկտրոնային փոստի օգտագործումը որպես օգտվողի անուն խորհուրդ չի տրվում: Շարունակե՞լ, այնուամենայնիվ:",
|
||||
"next_video_countdown": "Հաջորդ տեսանյութը նվագարկվում է {0} վրկ-ում"
|
||||
}
|
||||
}
|
@ -12,10 +12,14 @@
|
||||
"account": "Akun",
|
||||
"player": "Pemain",
|
||||
"livestreams": "Siaran Langsung",
|
||||
"channels": "Saluran"
|
||||
"channels": "Saluran",
|
||||
"bookmarks": "Markah",
|
||||
"channel_groups": "Grup saluran",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Tonton di {0}"
|
||||
"watch_on": "Tonton di {0}",
|
||||
"failed": "Gagal dengan kode kesalahan {0}, lihat catatan untuk info lebih lanjut"
|
||||
},
|
||||
"actions": {
|
||||
"subscribe": "Berlangganan - {count}",
|
||||
@ -41,18 +45,18 @@
|
||||
"audio_only": "Audio Saja",
|
||||
"default_quality": "Kualitas Bawaan",
|
||||
"buffering_goal": "Tujuan Buffering (dalam detik)",
|
||||
"country_selection": "Pemilihan Negara",
|
||||
"country_selection": "Negara",
|
||||
"default_homepage": "Halaman Beranda Bawaan",
|
||||
"show_comments": "Tampilkan Komentar",
|
||||
"minimize_description_default": "Kecilkan Deskripsi secara default",
|
||||
"language_selection": "Pemilihan Bahasa",
|
||||
"language_selection": "Bahasa",
|
||||
"instances_list": "Daftar Instansi",
|
||||
"enabled_codecs": "Kodek yang Diaktifkan (Beberapa)",
|
||||
"instance_selection": "Pemilihan Instansi",
|
||||
"instance_selection": "Instansi",
|
||||
"show_more": "Tampilkan Lebih Banyak",
|
||||
"yes": "Iya",
|
||||
"no": "Tidak",
|
||||
"import_from_json": "Impor dari JSON/CSV",
|
||||
"import_from_json": "Impor dari JSON",
|
||||
"loop_this_video": "Ulangi Video ini",
|
||||
"auto_play_next_video": "Mainkan video berikutnya secara otomatis",
|
||||
"donations": "Donasi pengembangan",
|
||||
@ -63,7 +67,7 @@
|
||||
"disable_lbry": "Nonaktifkan LBRY untuk Streaming",
|
||||
"enable_lbry_proxy": "Aktifkan Proksi untuk LBRY",
|
||||
"view_ssl_score": "Tampilkan Skor SSL",
|
||||
"search": "Telusuri",
|
||||
"search": "Telusuri (Ctrl+K)",
|
||||
"filter": "Saring",
|
||||
"loading": "Memuat...",
|
||||
"clear_history": "Hapus Riwayat",
|
||||
@ -89,7 +93,7 @@
|
||||
"logout": "Keluar dari perangkat ini",
|
||||
"minimize_recommendations_default": "Kecilkan Rekomendasi secara bawaan",
|
||||
"invalidate_session": "Keluarkan semua perangkat",
|
||||
"instance_auth_selection": "Pemilihan Instansi Otentikasi",
|
||||
"instance_auth_selection": "Instance Otentikasi",
|
||||
"different_auth_instance": "Gunakan instansi lain untuk otentikasi",
|
||||
"clone_playlist_success": "Berhasil disalin!",
|
||||
"clone_playlist": "Salin Daftar Putar",
|
||||
@ -98,8 +102,6 @@
|
||||
"restore_preferences": "Pulihkan preferensi",
|
||||
"confirm_reset_preferences": "Apakah Anda yakin ingin mengatur ulang preferensi Anda?",
|
||||
"backup_preferences": "Cadangkan preferensi",
|
||||
"rename_playlist": "Ubah nama daftar putar",
|
||||
"new_playlist_name": "Nama daftar putar baru",
|
||||
"share": "Bagikan",
|
||||
"with_timecode": "Bagikan dengan kode waktu",
|
||||
"piped_link": "Tautan Piped",
|
||||
@ -120,7 +122,31 @@
|
||||
"show_watch_on_youtube": "Tampilkan tombol Tonton di YouTube",
|
||||
"minimize_chapters_default": "Kecilkan Bab secara bawaan",
|
||||
"no_valid_playlists": "Berkas ini tidak berisi daftar putar yang valid!",
|
||||
"with_playlist": "Bagikan dengan daftar putar"
|
||||
"with_playlist": "Bagikan dengan daftar putar",
|
||||
"playlist_bookmarked": "Dimarkahi",
|
||||
"bookmark_playlist": "Markahi",
|
||||
"skip_button_only": "Tampilkan tombol lewati",
|
||||
"skip_automatically": "Secara otomatis",
|
||||
"min_segment_length": "Panjang Segmen Minimum (dalam detik)",
|
||||
"skip_segment": "Lewati Segmen",
|
||||
"show_less": "Tampilkan lebih sedikit",
|
||||
"autoplay_next_countdown": "Hitungan mundur bawaan sebelum video berikutnya (dalam detik)",
|
||||
"dismiss": "Abaikan",
|
||||
"create_group": "Buat grup",
|
||||
"group_name": "Nama grup",
|
||||
"auto_display_captions": "Tampilkan Takarir Secara Otomatis",
|
||||
"cancel": "Batal",
|
||||
"playlist_description": "Deskripsi daftar putar",
|
||||
"edit_playlist": "Sunting daftar putar",
|
||||
"playlist_name": "Nama daftar putar",
|
||||
"okay": "Oke",
|
||||
"show_search_suggestions": "Tampilkan saran pencarian",
|
||||
"chapters_layout_mobile": "Tata Letak Bab di Ponsel",
|
||||
"delete_automatically": "Hapus secara otomatis setelah",
|
||||
"enable_dearrow": "Aktifkan DeArrow",
|
||||
"generate_qrcode": "Buat Kode QR",
|
||||
"import_from_json_csv": "Impor dari JSON/CSV",
|
||||
"download_frame": "Unduh bingkai"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Dipasangi pin oleh {author}",
|
||||
@ -139,7 +165,9 @@
|
||||
},
|
||||
"login": {
|
||||
"username": "Nama Pengguna",
|
||||
"password": "Kata Sandi"
|
||||
"password": "Kata Sandi",
|
||||
"password_confirm": "Konfirmasi kata sandi",
|
||||
"passwords_incorrect": "Kata sandi tidak cocok!"
|
||||
},
|
||||
"video": {
|
||||
"videos": "Video",
|
||||
@ -149,7 +177,13 @@
|
||||
"ratings_disabled": "Penilaian Dinonaktifkan",
|
||||
"chapters": "Bagian",
|
||||
"live": "{0} Langsung",
|
||||
"shorts": "Shorts"
|
||||
"shorts": "Shorts",
|
||||
"all": "Semua",
|
||||
"category": "Kategori",
|
||||
"chapters_horizontal": "Horisontal",
|
||||
"chapters_vertical": "Vertikal",
|
||||
"license": "Lisensi",
|
||||
"visibility": "Visibilitas"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Apakah Anda bermaksud: {0}?",
|
||||
@ -160,7 +194,8 @@
|
||||
"music_videos": "YT Music: Video",
|
||||
"music_albums": "YT Music: Album",
|
||||
"music_playlists": "YT Music: Daftar Putar",
|
||||
"all": "YouTube: Semua"
|
||||
"all": "YouTube: Semua",
|
||||
"music_artists": "YT Music: Artis"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Berlangganan ke: {0}"
|
||||
@ -173,6 +208,12 @@
|
||||
"preferences_note": "Catatan: preferensi disimpan dalam penyimpanan lokal peramban Anda. Menghapus data peramban Anda akan mengatur ulang.",
|
||||
"copied": "Disalin!",
|
||||
"cannot_copy": "Tidak dapat menyalin!",
|
||||
"local_storage": "Tindakan ini membutuhkan localStorage, apakah kuki diaktifkan?"
|
||||
"local_storage": "Tindakan ini membutuhkan localStorage, apakah kuki diaktifkan?",
|
||||
"register_no_email_note": "Menggunakan surel sebagai nama pengguna tidak disarankan. Lanjut?",
|
||||
"next_video_countdown": "Memutar video berikutnya dalam {0} detik",
|
||||
"weeks": "{amount} minggu",
|
||||
"hours": "{amount} jam",
|
||||
"days": "{amount} hari",
|
||||
"months": "{amount} bulan"
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,9 @@
|
||||
"account": "Reikningur",
|
||||
"instance": "Tilvik",
|
||||
"livestreams": "Útsendingar í beinni",
|
||||
"channels": "Rásir"
|
||||
"channels": "Rásir",
|
||||
"bookmarks": "Bókamerki",
|
||||
"channel_groups": "Rásarhópar"
|
||||
},
|
||||
"actions": {
|
||||
"sort_by": "Raða eftir:",
|
||||
@ -94,8 +96,6 @@
|
||||
"instance_donations": "Framlög til netþjóns",
|
||||
"status_page": "Staða",
|
||||
"source_code": "Frumkóði",
|
||||
"rename_playlist": "Endurnefna spilunarlista",
|
||||
"new_playlist_name": "Nýtt heiti spilunarlista",
|
||||
"share": "Deila",
|
||||
"with_timecode": "Deilа með tímakóða",
|
||||
"piped_link": "Hlekkur Piped",
|
||||
|
@ -1,12 +1,12 @@
|
||||
{
|
||||
"actions": {
|
||||
"instances_list": "Elenco delle istanze",
|
||||
"language_selection": "Selezione della lingua",
|
||||
"language_selection": "Lingua",
|
||||
"store_watch_history": "Conserva la cronologia di visualizzazione",
|
||||
"minimize_description_default": "Minimizza la descrizione per impostazione predefinita",
|
||||
"show_comments": "Mostra i commenti",
|
||||
"default_homepage": "Pagina iniziale predefinita",
|
||||
"country_selection": "Selezione del paese",
|
||||
"country_selection": "Paese",
|
||||
"buffering_goal": "Obiettivo di buffering (in secondi)",
|
||||
"default_quality": "Qualità predefinita",
|
||||
"audio_only": "Solo audio",
|
||||
@ -37,7 +37,7 @@
|
||||
"enable_lbry_proxy": "Abilita il proxy per LBRY",
|
||||
"disable_lbry": "Disabilita LBRY per lo streaming",
|
||||
"show_description": "Mostra la descrizione",
|
||||
"minimize_description": "Minimizza la descrizione per impostazione predefinita",
|
||||
"minimize_description": "Minimizza descrizione",
|
||||
"minimize_recommendations": "Minimizza consigli",
|
||||
"show_recommendations": "Mostra consigli",
|
||||
"donations": "Donazioni per lo sviluppo",
|
||||
@ -48,10 +48,10 @@
|
||||
"no": "No",
|
||||
"yes": "Sì",
|
||||
"show_more": "Mostra di più",
|
||||
"instance_selection": "Selezione dell'istanza",
|
||||
"instance_selection": "Istanza",
|
||||
"loading": "Caricamento…",
|
||||
"filter": "Filtra",
|
||||
"search": "Cerca",
|
||||
"search": "Cerca (Ctrl+K)",
|
||||
"view_ssl_score": "Visualizza il punteggio SSL",
|
||||
"clear_history": "Cancella la cronologia",
|
||||
"load_more_replies": "Carica più risposte",
|
||||
@ -72,7 +72,7 @@
|
||||
"minimize_recommendations_default": "Riduci al minimo le raccomandazioni per impostazione predefinita",
|
||||
"different_auth_instance": "Usa un'istanza diversa per l'autenticazione",
|
||||
"invalidate_session": "Disconnetti su tutti i dispositivi",
|
||||
"instance_auth_selection": "Selezione dell'istanza di autenticazione",
|
||||
"instance_auth_selection": "Istanza di autenticazione",
|
||||
"clone_playlist_success": "Clonato con successo!",
|
||||
"clone_playlist": "Clona la playlist",
|
||||
"download_as_txt": "Scarica come .txt",
|
||||
@ -87,8 +87,6 @@
|
||||
"time_code": "Tempo (in secondi)",
|
||||
"follow_link": "Apri il collegamento",
|
||||
"with_timecode": "Condividi con marca temporale",
|
||||
"new_playlist_name": "Nuovo nome dalla playlist",
|
||||
"rename_playlist": "Rinomina la playlist",
|
||||
"show_chapters": "Capitoli",
|
||||
"store_search_history": "Memorizza la cronologia delle ricerche",
|
||||
"status_page": "Stato",
|
||||
@ -101,7 +99,25 @@
|
||||
"minimize_comments_default": "Minimizza i commenti per impostazione predefinita",
|
||||
"minimize_comments": "Minimizza i commenti",
|
||||
"minimize_chapters_default": "Minimizza i capitoli per impostazione predefinita",
|
||||
"no_valid_playlists": "Il file non contiene playlist valide!"
|
||||
"no_valid_playlists": "Il file non contiene playlist valide!",
|
||||
"bookmark_playlist": "Segnalibro",
|
||||
"with_playlist": "Condividi con la playlist",
|
||||
"playlist_bookmarked": "Nei segnalibri",
|
||||
"min_segment_length": "Lunghezza minima del segmento (in secondi)",
|
||||
"skip_automatically": "Automaticamente",
|
||||
"skip_button_only": "Mostra pulsante di salto",
|
||||
"skip_segment": "Salta segmento",
|
||||
"show_less": "Mostra meno",
|
||||
"autoplay_next_countdown": "Conto alla rovescia predefinito prima del video successivo (in secondi)",
|
||||
"cancel": "Annulla",
|
||||
"okay": "Va bene",
|
||||
"edit_playlist": "Modifica playlist",
|
||||
"playlist_name": "Nome playilist",
|
||||
"playlist_description": "Descrizione playlist",
|
||||
"group_name": "Nome gruppo",
|
||||
"create_group": "Crea gruppo",
|
||||
"show_search_suggestions": "Mostra suggerimenti di ricerca",
|
||||
"dismiss": "Chiudi"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Guarda su {0}"
|
||||
@ -119,7 +135,9 @@
|
||||
"instance": "Istanza",
|
||||
"player": "Riproduttore",
|
||||
"livestreams": "Streaming live",
|
||||
"channels": "Canali"
|
||||
"channels": "Canali",
|
||||
"bookmarks": "Segnalibri",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"video": {
|
||||
"sponsor_segments": "Segmenti sponsor",
|
||||
@ -129,7 +147,12 @@
|
||||
"ratings_disabled": "Valutazioni disabilitate",
|
||||
"live": "{0} Diretta",
|
||||
"chapters": "Capitoli",
|
||||
"shorts": "Short"
|
||||
"shorts": "Short",
|
||||
"all": "Tutti",
|
||||
"category": "Categoria",
|
||||
"chapters_horizontal": "Orizzontale",
|
||||
"chapters_vertical": "Verticale",
|
||||
"license": "Licenza"
|
||||
},
|
||||
"preferences": {
|
||||
"ssl_score": "Valutazione SSL",
|
||||
@ -159,7 +182,8 @@
|
||||
"channels": "YouTube: Canali",
|
||||
"music_songs": "YT Music: Canzoni",
|
||||
"all": "YouTube: Tutto",
|
||||
"videos": "YouTube: Video"
|
||||
"videos": "YouTube: Video",
|
||||
"music_artists": "YT Music: Artisti"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Abbonato a: {0}"
|
||||
@ -172,6 +196,8 @@
|
||||
"preferences_note": "Nota: le preferenze sono salvate nella memoria locale del tuo browser. L'eliminazione dei dati del tuo browser le ripristinerà.",
|
||||
"copied": "Copiato!",
|
||||
"cannot_copy": "Impossibile copiare!",
|
||||
"local_storage": "Questa azione richiede localStorage, i cookie sono abilitati?"
|
||||
"local_storage": "Questa azione richiede localStorage, i cookie sono abilitati?",
|
||||
"register_no_email_note": "L'utilizzo di un indirizzo e-mail come nome utente è sconsigliato. Continuare comunque?",
|
||||
"next_video_countdown": "Riproduzione prossimo video tra {0}s"
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,13 @@
|
||||
"player": "プレイヤー",
|
||||
"instance": "インスタンス",
|
||||
"channels": "チャンネル",
|
||||
"livestreams": "ライブ配信"
|
||||
"livestreams": "ライブ配信",
|
||||
"bookmarks": "ブックマーク",
|
||||
"channel_groups": "グループ",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "{0}で見る"
|
||||
"watch_on": "{0}で視聴"
|
||||
},
|
||||
"actions": {
|
||||
"subscribe": "チャンネル登録 - {count}",
|
||||
@ -27,37 +30,37 @@
|
||||
"channel_name_asc": "チャンネル名 (AからZ)",
|
||||
"channel_name_desc": "チャンネル名 (ZからA)",
|
||||
"back": "戻る",
|
||||
"uses_api_from": "API使用元 ",
|
||||
"enable_sponsorblock": "SponsorBlockを有効化",
|
||||
"uses_api_from": "API 提供元 ",
|
||||
"enable_sponsorblock": "SponsorBlock を使用",
|
||||
"skip_sponsors": "広告をスキップ",
|
||||
"skip_intro": "インターミッション/イントロアニメーションをスキップする",
|
||||
"skip_outro": "エンドカード/クレジットをスキップする",
|
||||
"skip_preview": "プレビュー/要約をスキップ",
|
||||
"skip_interaction": "インタラクションリマインダーをスキップする (チャンネル登録)",
|
||||
"skip_self_promo": "無償/自己プロモーションをスキップ",
|
||||
"skip_intro": "合間/導入アニメをスキップ",
|
||||
"skip_outro": "終了シーン/クレジットをスキップ",
|
||||
"skip_preview": "予告/あらすじをスキップ",
|
||||
"skip_interaction": "登録など操作を頼む自己宣伝をスキップ",
|
||||
"skip_self_promo": "無償または自己の宣伝をスキップ",
|
||||
"skip_non_music": "音楽: 非音楽部分をスキップ",
|
||||
"theme": "テーマ",
|
||||
"auto": "自動",
|
||||
"dark": "ダーク",
|
||||
"light": "ライト",
|
||||
"autoplay_video": "動画を自動再生",
|
||||
"audio_only": "音声のみ",
|
||||
"default_quality": "デフォルトの画質",
|
||||
"audio_only": "音声のみのモード",
|
||||
"default_quality": "標準の画質",
|
||||
"buffering_goal": "バッファリング目標値 (秒)",
|
||||
"country_selection": "国の選択",
|
||||
"default_homepage": "デフォルトのホームページ",
|
||||
"country_selection": "国",
|
||||
"default_homepage": "ホームに表示するページ",
|
||||
"show_comments": "コメントを表示",
|
||||
"minimize_description_default": "デフォルトで詳細を最小化する",
|
||||
"store_watch_history": "再生履歴を保存する",
|
||||
"language_selection": "言語の選択",
|
||||
"minimize_description_default": "最初から説明を最小化",
|
||||
"store_watch_history": "再生履歴を保存",
|
||||
"language_selection": "言語",
|
||||
"instances_list": "インスタンス一覧",
|
||||
"enabled_codecs": "コーデックの有効化 (複数選択)",
|
||||
"instance_selection": "インスタンスを選択",
|
||||
"instance_selection": "インスタンス",
|
||||
"show_more": "もっと見る",
|
||||
"yes": "はい",
|
||||
"no": "いいえ",
|
||||
"export_to_json": "JSONに出力",
|
||||
"import_from_json": "JSON/CSVを読み込む",
|
||||
"import_from_json": "JSONから読み込む",
|
||||
"loop_this_video": "この動画をループ再生",
|
||||
"auto_play_next_video": "次の動画を自動再生",
|
||||
"donations": "開発者に寄付",
|
||||
@ -66,60 +69,82 @@
|
||||
"minimize_recommendations": "おすすめを最小化",
|
||||
"show_recommendations": "おすすめを見る",
|
||||
"disable_lbry": "ストリーミングのLBRYを無効化",
|
||||
"enable_lbry_proxy": "LBRYプロキシをオン",
|
||||
"view_ssl_score": "SSLスコアを見る",
|
||||
"search": "検索",
|
||||
"enable_lbry_proxy": "LBRYにプロキシを使用",
|
||||
"view_ssl_score": "SSLの評価を表示",
|
||||
"search": "検索 (Ctrl+K)",
|
||||
"filter": "フィルター",
|
||||
"loading": "読み込み中…",
|
||||
"clear_history": "再生履歴を削除",
|
||||
"hide_replies": "返信を非表示",
|
||||
"load_more_replies": "リプライをもっと見る",
|
||||
"skip_filler_tangent": "無関係なコンテンツをスキップ",
|
||||
"load_more_replies": "返信をもっと見る",
|
||||
"skip_filler_tangent": "無関係な談話をスキップ",
|
||||
"skip_highlight": "ハイライトをスキップ",
|
||||
"add_to_playlist": "再生リストに追加する",
|
||||
"add_to_playlist": "再生リストに追加",
|
||||
"create_playlist": "再生リストを作成",
|
||||
"remove_from_playlist": "再生リストから削除",
|
||||
"delete_playlist_video_confirm": "再生リストからこの動画を削除しますか?",
|
||||
"delete_playlist": "再生リストを削除",
|
||||
"please_select_playlist": "再生リストを選択してください",
|
||||
"show_markers": "プレイヤーにマーカーを表示",
|
||||
"show_markers": "プレイヤーに目印の区切りを表示",
|
||||
"select_playlist": "再生リストを選択",
|
||||
"delete_playlist_confirm": "再生リストを削除しますか?",
|
||||
"delete_account": "アカウントを削除する",
|
||||
"store_search_history": "検索履歴を保存する",
|
||||
"delete_account": "アカウントを削除",
|
||||
"store_search_history": "検索履歴を保存",
|
||||
"show_chapters": "チャプター",
|
||||
"status_page": "状態",
|
||||
"source_code": "ソースコード",
|
||||
"instance_donations": "インスタンスに寄付",
|
||||
"minimize_comments": "コメントを最小化する",
|
||||
"minimize_comments": "コメントを最小化",
|
||||
"share": "共有",
|
||||
"with_timecode": "タイムコード付きで共有",
|
||||
"different_auth_instance": "認証に別のインスタンスを使う",
|
||||
"with_timecode": "時間指定",
|
||||
"different_auth_instance": "認証に別のインスタンスを使用",
|
||||
"download_as_txt": ".txtでダウンロード",
|
||||
"logout": "このデバイスでログアウト",
|
||||
"minimize_recommendations_default": "デフォルトでおすすめを最小化する",
|
||||
"logout": "この端末からログアウト",
|
||||
"minimize_recommendations_default": "最初からおすすめを最小化",
|
||||
"hide_watched": "再生済みの動画をフィードに表示しない",
|
||||
"minimize_chapters_default": "デフォルトでチャプターを最小化する",
|
||||
"show_watch_on_youtube": "\"YouTubeで見る\"ボタンを表示する",
|
||||
"invalidate_session": "すべてのデバイスでログアウトする",
|
||||
"instance_auth_selection": "認証インスタンスの選択",
|
||||
"minimize_chapters_default": "最初からチャプターを最小化",
|
||||
"show_watch_on_youtube": "「YouTubeで視聴」ボタンを表示",
|
||||
"invalidate_session": "すべての端末からログアウト",
|
||||
"instance_auth_selection": "認証用インスタンス",
|
||||
"clone_playlist_success": "複製に成功しました!",
|
||||
"backup_preferences": "設定をバックアップする",
|
||||
"restore_preferences": "設定を復元する",
|
||||
"backup_preferences": "設定をバックアップ",
|
||||
"restore_preferences": "設定を復元",
|
||||
"back_to_home": "ホームに戻る",
|
||||
"copy_link": "リンクをコピーする",
|
||||
"copy_link": "リンクコピー",
|
||||
"time_code": "タイムコード (秒)",
|
||||
"documentation": "ドキュメント",
|
||||
"reset_preferences": "設定をリセット",
|
||||
"reset_preferences": "設定を初期化",
|
||||
"confirm_reset_preferences": "設定をリセットしますか?",
|
||||
"rename_playlist": "プレイリスト名を変更する",
|
||||
"piped_link": "Pipedリンク",
|
||||
"new_playlist_name": "新しいプレイリスト名",
|
||||
"follow_link": "リンクに従う",
|
||||
"follow_link": "リンクを開く",
|
||||
"reply_count": "{count} 件の返信",
|
||||
"clone_playlist": "プレイリストを複製",
|
||||
"minimize_comments_default": "デフォルトでコメントを最小化する",
|
||||
"no_valid_playlists": "ファイルに有効なプレイリストが含まれていません。"
|
||||
"clone_playlist": "再生リストを複製",
|
||||
"minimize_comments_default": "最初からコメントを最小化",
|
||||
"no_valid_playlists": "このファイルは有効な再生リストではありません!",
|
||||
"playlist_bookmarked": "ブックマーク完了",
|
||||
"bookmark_playlist": "ブックマーク",
|
||||
"with_playlist": "再生リストで共有",
|
||||
"skip_automatically": "自動",
|
||||
"skip_button_only": "スキップボタン表示",
|
||||
"skip_segment": "ここをスキップ",
|
||||
"min_segment_length": "最小の区切りの長さ (秒)",
|
||||
"show_less": "少なく見る",
|
||||
"autoplay_next_countdown": "次の動画の再生までの時間 (秒)",
|
||||
"dismiss": "却下",
|
||||
"create_group": "グループ作成",
|
||||
"group_name": "グループ名",
|
||||
"auto_display_captions": "自動で字幕を表示",
|
||||
"okay": "OK",
|
||||
"cancel": "キャンセル",
|
||||
"edit_playlist": "再生リストを編集",
|
||||
"playlist_name": "再生リスト名",
|
||||
"playlist_description": "再生リストの説明",
|
||||
"chapters_layout_mobile": "モバイル端末でのチャプターの配置",
|
||||
"show_search_suggestions": "検索語句の候補を表示",
|
||||
"delete_automatically": "指定時間後に自動削除",
|
||||
"enable_dearrow": "DeArrow を使用",
|
||||
"generate_qrcode": "QRコードの生成",
|
||||
"import_from_json_csv": "JSON/CSVから読み込む"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "{author} によって固定",
|
||||
@ -130,25 +155,33 @@
|
||||
"preferences": {
|
||||
"instance_name": "インスタンス名",
|
||||
"instance_locations": "インスタンスの場所",
|
||||
"has_cdn": "CDNは存在する?",
|
||||
"ssl_score": "SSLスコア",
|
||||
"registered_users": "登録済みユーザー",
|
||||
"has_cdn": "CDNの有無",
|
||||
"ssl_score": "SSLの評価",
|
||||
"registered_users": "登録利用者数",
|
||||
"version": "バージョン",
|
||||
"up_to_date": "最新?"
|
||||
},
|
||||
"login": {
|
||||
"username": "ユーザー名",
|
||||
"password": "パスワード"
|
||||
"password": "パスワード",
|
||||
"password_confirm": "パスワードの確認",
|
||||
"passwords_incorrect": "パスワードが一致しません!"
|
||||
},
|
||||
"video": {
|
||||
"videos": "動画",
|
||||
"views": "{views} 回再生",
|
||||
"watched": "再生済み",
|
||||
"sponsor_segments": "スポンサーによる広告",
|
||||
"sponsor_segments": "広告シーン数",
|
||||
"ratings_disabled": "評価は無効化されています",
|
||||
"chapters": "チャプター",
|
||||
"live": "{0} ライブ配信",
|
||||
"shorts": "ショート"
|
||||
"shorts": "ショート",
|
||||
"all": "すべて",
|
||||
"category": "分類",
|
||||
"chapters_horizontal": "横方向",
|
||||
"chapters_vertical": "縦方向",
|
||||
"visibility": "公開状態",
|
||||
"license": "ライセンス"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "もしかして: {0}?",
|
||||
@ -159,14 +192,21 @@
|
||||
"music_songs": "YT Music: 音楽",
|
||||
"music_videos": "YT Music: 動画",
|
||||
"music_albums": "YT Music: アルバム",
|
||||
"music_playlists": "YT Music: 再生リスト"
|
||||
"music_playlists": "YT Music: 再生リスト",
|
||||
"music_artists": "YT Music: アーティスト"
|
||||
},
|
||||
"info": {
|
||||
"page_not_found": "ページが見つかりません",
|
||||
"copied": "コピーしました!",
|
||||
"cannot_copy": "コピーできません!",
|
||||
"preferences_note": "注意: 設定はブラウザのローカルストレージに保存されます。ブラウザのデータを削除するとリセットされます。",
|
||||
"local_storage": "この操作にはlocalStorageが必要です。Cookieは有効ですか?"
|
||||
"preferences_note": "注意: 設定は、お使いのブラウザの保存領域に保存されます。ブラウザのデータを削除すると初期化されます。",
|
||||
"local_storage": "この操作にはlocalStorageが必要です。Cookieは有効ですか?",
|
||||
"register_no_email_note": "ユーザー名としてのメールアドレスの使用は推奨しません。それでも続けますか?",
|
||||
"next_video_countdown": "{0} 秒後に次の動画",
|
||||
"days": "{amount}日",
|
||||
"weeks": "{amount}週",
|
||||
"hours": "{amount}時間",
|
||||
"months": "{amount}月"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "チャンネル登録: {0}"
|
||||
|
@ -6,7 +6,14 @@
|
||||
"history": "Amazray",
|
||||
"subscriptions": "Ijerriden",
|
||||
"account": "Amiḍan",
|
||||
"channels": "Ibuda"
|
||||
"channels": "Ibuda",
|
||||
"playlists": "Tabdert n tɣuri",
|
||||
"instance": "Tummant",
|
||||
"player": "Ameɣri",
|
||||
"livestreams": "Azuzer usrid",
|
||||
"bookmarks": "Ticraḍ",
|
||||
"feed": "Amultaɣ",
|
||||
"trending": "Tiddin"
|
||||
},
|
||||
"actions": {
|
||||
"dark": "Ubrik",
|
||||
@ -19,16 +26,148 @@
|
||||
"delete_playlist_confirm": "Kkes tabdart-a n tɣuri?",
|
||||
"share": "Bḍu",
|
||||
"documentation": "Tasemlit",
|
||||
"status_page": "État"
|
||||
"status_page": "État",
|
||||
"least_recent": "N melmi kna",
|
||||
"channel_name_desc": "Isem n ubadu (A-Z)",
|
||||
"channel_name_asc": "Isem n ubadu (A-z)",
|
||||
"back": "Tuɣalin",
|
||||
"uses_api_from": "Isseqdac API n: ",
|
||||
"enable_sponsorblock": "Rmed amsewḥal n udellel",
|
||||
"skip_sponsors": "Zgel adellel",
|
||||
"add_to_playlist": "Rnu ɣer tebdart n tɣuri",
|
||||
"hide_replies": "Ffer tiririyin",
|
||||
"load_more_replies": "Sali-d ugar n tririyin",
|
||||
"remove_from_playlist": "Kkes seg tebdart n tɣuri",
|
||||
"delete_playlist_video_confirm": "Kkes tavidyut seg tebdart n tɣuri?",
|
||||
"create_playlist": "Rnu tabdart n tɣuri",
|
||||
"subscribe": "Qqen - {count}",
|
||||
"unsubscribe": "Sefsex tuqqna n - {count}",
|
||||
"view_subscriptions": "Wali imuktaɣen",
|
||||
"sort_by": "Semyizwer s:",
|
||||
"most_recent": "Amaynut akk",
|
||||
"theme": "Asentel",
|
||||
"auto": "Awurman",
|
||||
"delete_playlist": "Kkes tabdart n tɣuri",
|
||||
"select_playlist": "Fren tabdart n tɣuri",
|
||||
"please_select_playlist": "Ttxil-k·m fren tabdart n tɣuri",
|
||||
"delete_account": "Kkes amiḍan",
|
||||
"logout": "Ffeɣ seg yibenk-a",
|
||||
"light": "D ameceɛlal",
|
||||
"autoplay_video": "Taɣuri tawurmant n tvidyut",
|
||||
"audio_only": "Ameslaw kan",
|
||||
"default_quality": "Taɣara tuzwirt",
|
||||
"auto_play_next_video": "Taɣuri tawurmant n tvidyut tuḍfirt",
|
||||
"donations": "Tawsa i usnefli",
|
||||
"disable_lbry": "Sens LBRY i usuddem",
|
||||
"enable_lbry_proxy": "Rmed apṛuksi i LBRY",
|
||||
"view_ssl_score": "Sken agmuḍ SSL",
|
||||
"show_recommendations": "Sken iwellihen",
|
||||
"clear_history": "Sfeḍ azray",
|
||||
"copy_link": "Nɣel aseɣwen",
|
||||
"time_code": "Tangalt n wakud (s tsinin)",
|
||||
"show_more": "Sken ugar",
|
||||
"export_to_json": "Sifeḍ ɣer JSON",
|
||||
"minimize_comments": "Semẓi iwenniten",
|
||||
"show_comments": "Sken iwenniten",
|
||||
"minimize_description": "Semẓi aglam",
|
||||
"show_description": "Sken aglam",
|
||||
"minimize_recommendations": "Semẓi iwellihen",
|
||||
"reply_count": "{count} tririyin",
|
||||
"bookmark_playlist": "Tacreḍt",
|
||||
"playlist_bookmarked": "Yettwacreḍ",
|
||||
"instances_list": "Tabdart n tummanin",
|
||||
"country_selection": "Afran n tmurt",
|
||||
"default_homepage": "Asebter agejdan amezwer",
|
||||
"instance_selection": "Afran n tummant",
|
||||
"import_from_json": "Kter seg JSON/CSV",
|
||||
"store_search_history": "Ḥrez azray n unadi",
|
||||
"instance_donations": "Tawsa n tummant",
|
||||
"source_code": "Tangalt taɣbalut",
|
||||
"minimize_description_default": "Semẓi aglam s wudem amezwer",
|
||||
"skip_highlight": "Zgel asebruraq",
|
||||
"minimize_comments_default": "Semẓi iwenniten s wudem amezwer",
|
||||
"store_watch_history": "Ḥrez azray n tmeẓriwt",
|
||||
"loop_this_video": "Err tavidyut-a d taẓayert",
|
||||
"minimize_recommendations_default": "Semẓi iwellihen s wudem amezwer",
|
||||
"no_valid_playlists": "Afaylu ulac deg-s tibdarin n tɣuri timeɣta!",
|
||||
"with_playlist": "Bḍu s tebdart n tɣuri",
|
||||
"skip_preview": "Zgel Taskant/Agzul",
|
||||
"skip_outro": "Zgel ismawen n taggara",
|
||||
"minimize_chapters_default": "Semẓi ixfawen s wudem uzwir",
|
||||
"confirm_reset_preferences": "D tidet tebɣiḍ ad twennzeḍ ismenyifen-ik•im?",
|
||||
"backup_preferences": "Ḥrez ismenyifen",
|
||||
"restore_preferences": "Err-d ismenyifen",
|
||||
"back_to_home": "Uɣal ɣer ugejdan",
|
||||
"follow_link": "Ḍfer aseɣwen",
|
||||
"show_chapters": "Ixfawen",
|
||||
"show_watch_on_youtube": "Sken taqeffalt Wali ɣef YouTube",
|
||||
"reset_preferences": "Wennez ismenyifen",
|
||||
"with_timecode": "Bḍu s tengalt n wakud",
|
||||
"hide_watched": "Ffer tividyutin yemmeẓren deg usuddel",
|
||||
"skip_interaction": "Zgel ismektiyen n umyigew (Multeɣ)",
|
||||
"enabled_codecs": "Isettengal ttwaremden (aṭas)",
|
||||
"buffering_goal": "Iswi n uḥraz akudan (s tsinin)",
|
||||
"skip_non_music": "Zgel aẓawan: tafrant ur nelli d aẓawan",
|
||||
"show_markers": "Sken ticraḍ ɣef umeɣri",
|
||||
"instance_auth_selection": "Tafrant n tummant n usesteb",
|
||||
"invalidate_session": "Ffeɣ seg meṛṛa ibenkan",
|
||||
"different_auth_instance": "Seqdec tummant tayeḍ i usesteb",
|
||||
"download_as_txt": "Sader am.txt",
|
||||
"piped_link": "Aseɣwen n Piped",
|
||||
"clone_playlist": "Tabdart n tɣuri yemtawan"
|
||||
},
|
||||
"preferences": {
|
||||
"version": "Lqem"
|
||||
"version": "Lqem",
|
||||
"has_cdn": "Ɣur-s CDN?",
|
||||
"registered_users": "Iseqdacen yettwajerrden",
|
||||
"up_to_date": "D amaynut?",
|
||||
"ssl_score": "Agmuḍ SSL",
|
||||
"instance_name": "Isem n tummant",
|
||||
"instance_locations": "Idgan n tummant"
|
||||
},
|
||||
"login": {
|
||||
"username": "Nom d'utilisateur",
|
||||
"password": "Awal n uɛeddi"
|
||||
},
|
||||
"video": {
|
||||
"videos": "Tividyutin"
|
||||
"videos": "Tividyutin",
|
||||
"views": "{views} tmeẓriwin",
|
||||
"watched": "Yemẓer",
|
||||
"shorts": "Tiwezlanin",
|
||||
"live": "{0} srid",
|
||||
"sponsor_segments": "Inegzumen n udellel",
|
||||
"chapters": "Ixfawen",
|
||||
"ratings_disabled": "Iktazalen ttwasensen"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Wali deg {0}"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Isenteḍ-itt {author}",
|
||||
"loading": "Asali n yiwenniten...",
|
||||
"disabled": "Ameskar issens iwenniten.",
|
||||
"user_disabled": "Nsan yiwenniten deg Yiɣewwaren."
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Tebɣiḍ ad d-tiniḍ: {0}?",
|
||||
"music_playlists": "YT Music: Tibdarin n tɣuri",
|
||||
"all": "YouTube: Akk",
|
||||
"videos": "YouTube: Tividyutin",
|
||||
"channels": "YouTube: Ibuda",
|
||||
"music_videos": "YT Music: Tividyutin",
|
||||
"playlists": "YouTube: Tibdarin n tɣuri",
|
||||
"music_songs": "YT Music: Tizlatin",
|
||||
"music_albums": "YT Music: Albumen"
|
||||
},
|
||||
"info": {
|
||||
"copied": "Yettwanɣel!",
|
||||
"page_not_found": "Ur yettwaf ara usebter",
|
||||
"cannot_copy": "D awezɣi ad d-yettwanɣel!",
|
||||
"register_no_email_note": "Aseqdec n yimayl am yisem n useqdac, ur yettusireg ara. Kemmel ɣas akken?",
|
||||
"local_storage": "Tigawt-a aḥraz adigan, inagan n tuqqna remden?",
|
||||
"preferences_note": "Tamawt: ismenyifen ttwaskelsen deg uklas adigan n yiminig-ik·im. Tukksa n yisefka yiminig-ik·im ad ten-iwennez."
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Imulteɣ ɣer: {0}"
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
"show_comments": "댓글 보이기",
|
||||
"unsubscribe": "구독 취소 - {count}",
|
||||
"view_subscriptions": "구독 보기",
|
||||
"least_recent": "가장 오래된",
|
||||
"least_recent": "오래된 순",
|
||||
"theme": "테마",
|
||||
"auto": "자동",
|
||||
"channel_name_desc": "채널 이름 (Z-A)",
|
||||
@ -26,16 +26,16 @@
|
||||
"no": "아니요",
|
||||
"loop_this_video": "이 동영상 반복",
|
||||
"auto_play_next_video": "다음 동영상 자동 재생",
|
||||
"minimize_description": "설명 최소화",
|
||||
"minimize_description": "설명 가리기",
|
||||
"show_recommendations": "추천 동영상 표시",
|
||||
"sort_by": "정렬:",
|
||||
"most_recent": "가장 최신",
|
||||
"most_recent": "최신 순",
|
||||
"channel_name_asc": "채널 이름 (A-Z)",
|
||||
"subscribe": "구독 - {count}",
|
||||
"audio_only": "오디오만",
|
||||
"skip_sponsors": "스폰서 스킵",
|
||||
"dark": "다크",
|
||||
"minimize_description_default": "기본적으로 설명 최소화",
|
||||
"minimize_description_default": "설명 가리기를 기본 설정값으로",
|
||||
"enabled_codecs": "활성화된 코덱 (여러 개)",
|
||||
"instance_selection": "인스턴스 선택",
|
||||
"import_from_json": "JSON/CSV에서 가져오기",
|
||||
@ -50,11 +50,11 @@
|
||||
"show_description": "설명 표시",
|
||||
"disable_lbry": "LBRY 스트리밍 비활성화",
|
||||
"enable_lbry_proxy": "LBRY 프록시 활성화",
|
||||
"minimize_recommendations": "추천 동영상 최소화",
|
||||
"minimize_recommendations": "추천 동영상 가리기",
|
||||
"loading": "로딩...",
|
||||
"view_ssl_score": "SSL 점수 보기",
|
||||
"skip_intro": "중간 휴식/인트로 애니메이션 스킵",
|
||||
"search": "검색",
|
||||
"search": "검색 (Ctrl+K)",
|
||||
"clear_history": "기록 지우기",
|
||||
"skip_highlight": "하이라이트 스킵",
|
||||
"select_playlist": "재생목록 선택",
|
||||
@ -69,8 +69,6 @@
|
||||
"logout": "이 기기에서 로그아웃",
|
||||
"show_chapters": "챕터",
|
||||
"download_as_txt": ".txt로 다운로드",
|
||||
"new_playlist_name": "새 재생목록 이름",
|
||||
"rename_playlist": "재생목록 이름 변경",
|
||||
"share": "공유",
|
||||
"copy_link": "링크 복사",
|
||||
"time_code": "시작 시간 (초)",
|
||||
@ -84,7 +82,7 @@
|
||||
"restore_preferences": "설정 복원",
|
||||
"backup_preferences": "설정 백업",
|
||||
"back_to_home": "홈으로 가기",
|
||||
"minimize_recommendations_default": "기본적으로 추천 동영상 최소화",
|
||||
"minimize_recommendations_default": "추천 동영상 가리기를 기본 설정값으로",
|
||||
"invalidate_session": "모든 기기에서 로그아웃",
|
||||
"instance_auth_selection": "인증 인스턴스 선택",
|
||||
"different_auth_instance": "인증에 다른 인스턴스 사용",
|
||||
@ -95,7 +93,17 @@
|
||||
"documentation": "문서",
|
||||
"source_code": "소스 코드",
|
||||
"instance_donations": "인스턴스 기부",
|
||||
"status_page": "상태"
|
||||
"status_page": "상태",
|
||||
"bookmark_playlist": "북마크",
|
||||
"dismiss": "무시",
|
||||
"minimize_comments_default": "댓글 가리기를 기본 설정값으로",
|
||||
"minimize_comments": "댓글 가리기",
|
||||
"show_watch_on_youtube": "‘YouTube에서 보기’ 버튼 표시",
|
||||
"minimize_chapters_default": "챕터 가리기를 기본 설정값으로",
|
||||
"autoplay_next_countdown": "다음 영상 재생까지 대기 시간(초)",
|
||||
"skip_button_only": "스킵 버튼 표시",
|
||||
"skip_automatically": "자동",
|
||||
"show_less": "덜 보기"
|
||||
},
|
||||
"titles": {
|
||||
"feed": "피드",
|
||||
@ -108,7 +116,10 @@
|
||||
"playlists": "재생목록",
|
||||
"account": "계정",
|
||||
"instance": "인스턴스",
|
||||
"player": "플레이어"
|
||||
"player": "플레이어",
|
||||
"bookmarks": "북마크",
|
||||
"livestreams": "실시간",
|
||||
"channels": "채널"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "에서 보기 {0}"
|
||||
@ -140,7 +151,8 @@
|
||||
"ratings_disabled": "등급 비활성화됨",
|
||||
"live": "{0} 라이브",
|
||||
"shorts": "Shorts",
|
||||
"chapters": "챕터"
|
||||
"chapters": "챕터",
|
||||
"category": "카테고리"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "이것을 찾으셨나요: {0}?",
|
||||
|
@ -80,7 +80,6 @@
|
||||
"reply_count": "{count} atsakymai",
|
||||
"show_chapters": "Skirsniai",
|
||||
"piped_link": "Piped nuoroda",
|
||||
"rename_playlist": "Pervardyti grojaraštį",
|
||||
"follow_link": "Sekti nuorodą",
|
||||
"store_search_history": "Išsaugoti paieškos istoriją",
|
||||
"hide_watched": "Slėpti žiūrėtus vaizdo įrašus sklaidos kanale",
|
||||
@ -88,7 +87,6 @@
|
||||
"status_page": "Būsena",
|
||||
"copy_link": "Kopijuoti nuorodą",
|
||||
"share": "Dalintis",
|
||||
"new_playlist_name": "Naujas grojaraščio pavadinimas",
|
||||
"minimize_recommendations_default": "Sumažinti rekomendacijas automatiškai",
|
||||
"instance_donations": "Perdavimo šaltinio parama",
|
||||
"instance_auth_selection": "Autentifikavimo perdavimo šaltinio pasirinkimas",
|
||||
|
@ -7,7 +7,9 @@
|
||||
"feed": "ഫീഡ്",
|
||||
"login": "പ്രവേശിക്കുക",
|
||||
"subscriptions": "സബ്സ്ക്രിപ്ഷനുകൾ",
|
||||
"playlists": "പ്ലേലിസ്റ്റുകൾ"
|
||||
"playlists": "പ്ലേലിസ്റ്റുകൾ",
|
||||
"player": "കളിക്കാരൻ",
|
||||
"account": "അക്കോണട്"
|
||||
},
|
||||
"actions": {
|
||||
"view_subscriptions": "സബ്സ്ക്രിപ്ഷനുകൾ കാണുക",
|
||||
@ -54,7 +56,7 @@
|
||||
"yes": "അതെ",
|
||||
"show_more": "കൂടുതൽ കാണിക്കുക",
|
||||
"buffering_goal": "ബഫറിംഗ് ലക്ഷ്യം(സെക്കൻഡുകളിൽ)",
|
||||
"import_from_json": "JSON/CSV നിന്ന് ഇറക്കുമതി ചെയ്യൂ",
|
||||
"import_from_json": "JSONിൽ നിന്ന് ഇറക്കുമതി ചെയ്യൂ",
|
||||
"export_to_json": "JSON-ലേക്ക് എക്സ്പ്പോർട്ട് ചെയ്യുക",
|
||||
"instance_selection": "ഇൻസ്റ്റ്ൻസ് തിരഞ്ഞെടുക്കുക",
|
||||
"loading": "ലഭ്യമാക്കുന്നു...",
|
||||
@ -72,16 +74,33 @@
|
||||
"select_playlist": "ഒരു പ്ലേലിസ്റ്റ് തിരഞ്ഞെടുക്കൂ",
|
||||
"please_select_playlist": "ഒരു പ്ലേലിസ്റ്റ് തിരഞ്ഞെടുക്കുക",
|
||||
"delete_playlist_video_confirm": "ഈ പ്ലേലിസ്റ്റിൽ നിന്ന് ഈ വീഡിയോ ഒഴിവാക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുണ്ടോ?",
|
||||
"delete_playlist_confirm": "ഈ പ്ലേലിസ്റ്റ് ഇല്ലാതാക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുണ്ടൊ?"
|
||||
"delete_playlist_confirm": "ഈ പ്ലേലിസ്റ്റ് ഇല്ലാതാക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുണ്ടൊ?",
|
||||
"skip_automatically": "സ്വയമേവ",
|
||||
"show_watch_on_youtube": "YouTubeിൽ കാണാം എന്ന button കാണിക്കുകാ",
|
||||
"time_code": "സമയമായം (സെക്കന്റുകളിൽ)",
|
||||
"show_less": "കുറച്ച്മാതറം",
|
||||
"with_timecode": "സമയമായവുമായി പങ്കുവെക്കുക",
|
||||
"back_to_home": "തിരിച്ച് വീട്ടിലേക്ക്",
|
||||
"dismiss": "തിരിച്ച്",
|
||||
"create_group": "കൂട്ടം ഉണടാക്കുകാ",
|
||||
"okay": "ശരി",
|
||||
"invalidate_session": "എല ടിവയഡിൽ നിന്നും ലൊഗൗഠ അവുകാ",
|
||||
"enabled_codecs": "ഉപയോഗിക്കുന്ന കോടെക്കൃകൽ",
|
||||
"share": "പങ്കുവെക്കുക",
|
||||
"documentation": "സഹായക്കുറിപ്പുകൽ",
|
||||
"cancel": "റദ്ദാക്കുക",
|
||||
"generate_qrcode": "QR Code ഉണ്ടാക്കുക",
|
||||
"import_from_json_csv": "JSON/CSVിൽ നിന്ന് ഇറക്കുമതി ചെയ്യൂ"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "കാണുക {0}"
|
||||
"watch_on": "{0}ിൻ കാണൃകാ"
|
||||
},
|
||||
"video": {
|
||||
"watched": "കണ്ടതാണ്",
|
||||
"views": "{views} കാഴ്ചകൾ",
|
||||
"videos": "വിഡിയോകൾ",
|
||||
"sponsor_segments": "സ്പോൺസർമാരുടെ ഭാഗങ്ങൾ"
|
||||
"sponsor_segments": "സ്പോൺസർമാരുടെ ഭാഗങ്ങൾ",
|
||||
"all": "എല്ലാം"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "പിൻ ചെയ്തിരിക്കുന്നത് {author}"
|
||||
@ -96,5 +115,8 @@
|
||||
"login": {
|
||||
"password": "രഹസ്യവാക്ക്",
|
||||
"username": "ഉപയോക്തൃനാമം"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "{0} ആണൊ ഉദേശിച്ചെ?"
|
||||
}
|
||||
}
|
||||
|
@ -81,8 +81,6 @@
|
||||
"confirm_reset_preferences": "Tilbakestill alle innstillingene?",
|
||||
"restore_preferences": "Gjenopprett innstillinger",
|
||||
"show_chapters": "Kapitler",
|
||||
"rename_playlist": "Gi spillelisten ny navn",
|
||||
"new_playlist_name": "Nytt spillelistenavn",
|
||||
"share": "Del",
|
||||
"with_timecode": "Del med tidskode",
|
||||
"piped_link": "Piped-lenke",
|
||||
|
@ -1,108 +1,130 @@
|
||||
{
|
||||
"actions": {
|
||||
"skip_sponsors": "Sponsors Overslaan",
|
||||
"skip_outro": "Eindkaarten/Credits overslaan",
|
||||
"add_to_playlist": "Aan Afspeellijst Toevoegen",
|
||||
"sort_by": "Sorteer op:",
|
||||
"skip_sponsors": "Sponsors overslaan",
|
||||
"skip_outro": "Eindkaarten/credits overslaan",
|
||||
"add_to_playlist": "Toevoegen aan afspeellijst",
|
||||
"sort_by": "Sorteren op:",
|
||||
"buffering_goal": "Bufferdoel (in seconden)",
|
||||
"country_selection": "Land Selectie",
|
||||
"show_recommendations": "Aanbevelingen Weergeven",
|
||||
"disable_lbry": "LBRY voor Streamen Uitschakelen",
|
||||
"country_selection": "Land",
|
||||
"show_recommendations": "Aanbevelingen tonen",
|
||||
"disable_lbry": "LBRY voor streamen uitschakelen",
|
||||
"enable_lbry_proxy": "Proxy voor LBRY Inschakelen",
|
||||
"view_ssl_score": "SSL-score Bekijken",
|
||||
"search": "Zoeken",
|
||||
"search": "Zoeken (Ctrl+K)",
|
||||
"filter": "Filter",
|
||||
"skip_filler_tangent": "Opvultangens Overslaan",
|
||||
"theme": "Thema",
|
||||
"subscribe": "Abonneren - {count}",
|
||||
"skip_non_music": "Muziek Overslaan: Niet-muzieksectie",
|
||||
"show_comments": "Toon Reacties",
|
||||
"skip_self_promo": "Onbetaalde/Zelf-promotie Overslaan",
|
||||
"show_comments": "Opmerkingen tonen",
|
||||
"skip_self_promo": "Onbetaalde-/zelfpromotie overslaan",
|
||||
"skip_highlight": "Markering Overslaan",
|
||||
"skip_interaction": "Interactieherinnering Overslaan (Abonneren)",
|
||||
"show_more": "Toon Meer",
|
||||
"skip_interaction": "Interactieherinnering overslaan (abonneren)",
|
||||
"show_more": "Meer tonen",
|
||||
"unsubscribe": "Afmelden - {count}",
|
||||
"view_subscriptions": "Abonnementen Bekijken",
|
||||
"enable_sponsorblock": "Sponsorblok Inschakelen",
|
||||
"skip_preview": "Voorbeeld/Samenvatting Overslaan",
|
||||
"view_subscriptions": "Abonnementen bekijken",
|
||||
"enable_sponsorblock": "Sponsorblok inschakelen",
|
||||
"skip_preview": "Voorbeschouwing/samenvatting overslaan",
|
||||
"auto": "Auto",
|
||||
"dark": "Donker",
|
||||
"light": "Licht",
|
||||
"default_quality": "Standaard Kwaliteit",
|
||||
"loop_this_video": "Deze Video Herhalen",
|
||||
"loop_this_video": "Deze video herhalen",
|
||||
"donations": "Ontwikkelingsdonaties",
|
||||
"minimize_description": "Beschrijving Minimaliseren",
|
||||
"show_description": "Toon Beschrijving",
|
||||
"minimize_recommendations": "Aanbevelingen Minimaliseren",
|
||||
"most_recent": "Meest Recente",
|
||||
"least_recent": "Minst Recente",
|
||||
"minimize_description": "Omschrijving minimaliseren",
|
||||
"show_description": "Omschrijving tonen",
|
||||
"minimize_recommendations": "Aanbevelingen minimaliseren",
|
||||
"most_recent": "Meest recent",
|
||||
"least_recent": "Minst recent",
|
||||
"channel_name_asc": "Kanaalnaam (A-Z)",
|
||||
"channel_name_desc": "Kanaalnaam (Z-A)",
|
||||
"back": "Terug",
|
||||
"uses_api_from": "Gebruikt de API van ",
|
||||
"skip_intro": "Pauze/Intro-animatie Overslaan",
|
||||
"uses_api_from": "API gebruiken van ",
|
||||
"skip_intro": "Onderbrekings-/intro-animatie overslaan",
|
||||
"autoplay_video": "Video Automatisch Afspelen",
|
||||
"store_watch_history": "Kijkgeschiedenis Opslaan",
|
||||
"loading": "Laden...",
|
||||
"audio_only": "Alleen Audio",
|
||||
"default_homepage": "Standaard Startpagina",
|
||||
"minimize_description_default": "Beschrijving Standaard Minimaliseren",
|
||||
"language_selection": "Taalkeuze",
|
||||
"minimize_description_default": "Omschrijving standaard minimaliseren",
|
||||
"language_selection": "Taal",
|
||||
"instances_list": "Instantieslijst",
|
||||
"yes": "Ja",
|
||||
"export_to_json": "Exporteren naar JSON",
|
||||
"hide_replies": "Verberg Antwoorden",
|
||||
"hide_replies": "Reacties verbergen",
|
||||
"enabled_codecs": "Ingeschakelde Codecs (Meerdere)",
|
||||
"no": "Nee",
|
||||
"auto_play_next_video": "Volgende Video Automatisch Afspelen",
|
||||
"remove_from_playlist": "Uit Afspeellijst Verwijderen",
|
||||
"select_playlist": "Selecteer een Afspeellijst",
|
||||
"auto_play_next_video": "Volgende video automatisch afspelen",
|
||||
"remove_from_playlist": "Uit afspeellijst verwijderen",
|
||||
"select_playlist": "Afspeellijst selecteren",
|
||||
"delete_playlist_confirm": "Deze afspeellijst verwijderen?",
|
||||
"please_select_playlist": "Kies een afspeellijst a.u.b.",
|
||||
"instance_selection": "Instantie Selectie",
|
||||
"import_from_json": "Importeren uit JSON/CSV",
|
||||
"clear_history": "Geschiedenis Wissen",
|
||||
"load_more_replies": "Laad meer Antwoorden",
|
||||
"delete_playlist_video_confirm": "Video van playlist verwijderen?",
|
||||
"create_playlist": "Afspeellijst Maken",
|
||||
"delete_playlist": "Afspeellijst Verwijderen",
|
||||
"show_markers": "Toon markeringen op Speler",
|
||||
"store_search_history": "Zoekgeschiedenis opslaan",
|
||||
"please_select_playlist": "Selecteer een afspeellijst",
|
||||
"instance_selection": "Instantie",
|
||||
"import_from_json": "Importeren uit JSON",
|
||||
"clear_history": "Geschiedenis wissen",
|
||||
"load_more_replies": "Meer reacties laden",
|
||||
"delete_playlist_video_confirm": "Video uit deze afspeellijst verwijderen?",
|
||||
"create_playlist": "Afspeellijst aanmaken",
|
||||
"delete_playlist": "Afspeellijst verwijderen",
|
||||
"show_markers": "Laat markeringen op speler zien",
|
||||
"store_search_history": "Zoekgeschiedenis bijhouden",
|
||||
"minimize_chapters_default": "Hoofdstukken standaard minimaliseren",
|
||||
"show_watch_on_youtube": "Toon Bekijk op YouTube knop",
|
||||
"show_watch_on_youtube": "De knop ‘Bekijken op YouTube’ tonen",
|
||||
"restore_preferences": "Voorkeuren herstellen",
|
||||
"with_timecode": "Delen met tijdcode",
|
||||
"piped_link": "Piped link",
|
||||
"follow_link": "Volg link",
|
||||
"piped_link": "Piped-link",
|
||||
"follow_link": "Volglink",
|
||||
"copy_link": "Link kopiëren",
|
||||
"hide_watched": "Verberg bekeken video's in de feed",
|
||||
"hide_watched": "Bekeken video's in feed verbergen",
|
||||
"minimize_comments": "Opmerkingen minimaliseren",
|
||||
"instance_auth_selection": "Autenticatie Instantie Selectie",
|
||||
"clone_playlist": "Afspeellijst klonen",
|
||||
"instance_auth_selection": "Authenticatie-instantie",
|
||||
"clone_playlist": "Afspeellijst dupliceren",
|
||||
"download_as_txt": "Downloaden als .txt",
|
||||
"rename_playlist": "Afspeellijst hernoemen",
|
||||
"new_playlist_name": "Nieuwe afspeellijstnaam",
|
||||
"share": "Delen",
|
||||
"documentation": "Documentatie",
|
||||
"status_page": "Status",
|
||||
"time_code": "Tijdcode (in seconden)",
|
||||
"show_chapters": "Hoofdstukken",
|
||||
"source_code": "Broncode",
|
||||
"instance_donations": "Instantie donaties",
|
||||
"reply_count": "{count} antwoorden",
|
||||
"instance_donations": "Instantiedonaties",
|
||||
"reply_count": "{count} reacties",
|
||||
"no_valid_playlists": "Het bestand bevat geen geldige afspeellijsten!",
|
||||
"clone_playlist_success": "Succesvol gekloond!",
|
||||
"reset_preferences": "Voorkeuren opnieuw instellen",
|
||||
"clone_playlist_success": "Dupliceren gelukt!",
|
||||
"reset_preferences": "Voorkeuren resetten",
|
||||
"back_to_home": "Terug naar de start",
|
||||
"minimize_comments_default": "Opmerkingen standaard minimaliseren",
|
||||
"delete_account": "Account Verwijderen",
|
||||
"logout": "Uitloggen van dit apparaat",
|
||||
"delete_account": "Account verwijderen",
|
||||
"logout": "Uitloggen op dit apparaat",
|
||||
"minimize_recommendations_default": "Aanbevelingen standaard minimaliseren",
|
||||
"confirm_reset_preferences": "Weet u zeker dat u uw voorkeuren opnieuw wilt instellen?",
|
||||
"backup_preferences": "Back-up voorkeuren",
|
||||
"invalidate_session": "Alle apparaten afmelden",
|
||||
"confirm_reset_preferences": "Weet u zeker dat u uw voorkeuren wilt resetten?",
|
||||
"backup_preferences": "Back-up-voorkeuren",
|
||||
"invalidate_session": "Uitloggen op alle apparaten",
|
||||
"different_auth_instance": "Gebruik een andere instantie voor authenticatie",
|
||||
"with_playlist": "Delen met afspeellijst"
|
||||
"with_playlist": "Delen met afspeellijst",
|
||||
"playlist_bookmarked": "Bladwijzer gemaakt",
|
||||
"bookmark_playlist": "Bladwijzer",
|
||||
"skip_automatically": "Automatisch",
|
||||
"skip_button_only": "Overslaan-knop tonen",
|
||||
"min_segment_length": "Minimale segmentlengte (in seconden)",
|
||||
"skip_segment": "segment overslaan",
|
||||
"show_less": "Minder tonen",
|
||||
"autoplay_next_countdown": "Standaard aftellen tot de volgende video (in seconden)",
|
||||
"dismiss": "Afwijzen",
|
||||
"enable_dearrow": "DeArrow inschakelen",
|
||||
"playlist_description": "Afspeellijstomschrijving",
|
||||
"cancel": "Annuleren",
|
||||
"show_search_suggestions": "Zoeksuggesties tonen",
|
||||
"delete_automatically": "Automatisch verwijderen na",
|
||||
"okay": "Oké",
|
||||
"playlist_name": "Afspeellijstnaam",
|
||||
"edit_playlist": "Afspeellijst bewerken",
|
||||
"create_group": "Groep aanmaken",
|
||||
"group_name": "Groepnaam",
|
||||
"generate_qrcode": "QR-code genereren",
|
||||
"chapters_layout_mobile": "Mobiele lay-out voor hoofdstukken",
|
||||
"auto_display_captions": "Ondertiteling automatisch tonen",
|
||||
"import_from_json_csv": "Importeren uit JSON/CSV",
|
||||
"download_frame": "Beeld downloaden"
|
||||
},
|
||||
"titles": {
|
||||
"register": "Registreren",
|
||||
@ -117,25 +139,32 @@
|
||||
"instance": "Instantie",
|
||||
"player": "Speler",
|
||||
"livestreams": "Livestreams",
|
||||
"channels": "Kanalen"
|
||||
"channels": "Kanalen",
|
||||
"bookmarks": "Bladwijzers",
|
||||
"dearrow": "DeArrow",
|
||||
"channel_groups": "Kanaalgroepen"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Kijk op {0}"
|
||||
"watch_on": "Kijken op {0}",
|
||||
"failed": "Mislukt met foutcode {0}, zie logboeken voor meer informatie"
|
||||
},
|
||||
"search": {
|
||||
"videos": "YouTube: Video's",
|
||||
"channels": "YouTube: Kanalen",
|
||||
"playlists": "YouTube: Afspeellijsten",
|
||||
"music_songs": "YT Muziek: Liedjes",
|
||||
"music_videos": "YT Muziek: Video's",
|
||||
"music_albums": "YT Muziek: Albums",
|
||||
"music_playlists": "YT Muziek: Afspeellijsten",
|
||||
"music_songs": "YT Music: Nummers",
|
||||
"music_videos": "YT Music: Video's",
|
||||
"music_albums": "YT Music: Albums",
|
||||
"music_playlists": "YT Music: Afspeellijsten",
|
||||
"did_you_mean": "Bedoelde u: {0}?",
|
||||
"all": "YouTube: Alles"
|
||||
"all": "YouTube: Alles",
|
||||
"music_artists": "YT Music: Artiesten"
|
||||
},
|
||||
"login": {
|
||||
"username": "Gebruikersnaam",
|
||||
"password": "Wachtwoord"
|
||||
"password": "Wachtwoord",
|
||||
"password_confirm": "Wachtwoord bevestigen",
|
||||
"passwords_incorrect": "Wachtwoorden komen niet overeen!"
|
||||
},
|
||||
"video": {
|
||||
"videos": "Video's",
|
||||
@ -143,31 +172,43 @@
|
||||
"chapters": "Hoofdstukken",
|
||||
"watched": "Gekeken",
|
||||
"sponsor_segments": "Sponsorsegmenten",
|
||||
"ratings_disabled": "Beoordelingen Uitgeschakeld",
|
||||
"live": "{0} Live",
|
||||
"shorts": "Shorts"
|
||||
"ratings_disabled": "Beoordelingen uitgeschakeld",
|
||||
"live": "{0} live",
|
||||
"shorts": "Shorts",
|
||||
"category": "Categorie",
|
||||
"all": "Alle",
|
||||
"chapters_horizontal": "Horizontaal",
|
||||
"chapters_vertical": "Verticaal",
|
||||
"license": "Licentie",
|
||||
"visibility": "Zichtbaarheid"
|
||||
},
|
||||
"preferences": {
|
||||
"has_cdn": "Heeft CDN?",
|
||||
"registered_users": "Geregistreerde Gebruikers",
|
||||
"instance_name": "Instantie Naam",
|
||||
"instance_locations": "Locaties van Instanties",
|
||||
"registered_users": "Geregistreerde gebruikers",
|
||||
"instance_name": "Instantienaam",
|
||||
"instance_locations": "Instantielocaties",
|
||||
"version": "Versie",
|
||||
"up_to_date": "Bijgewerkt?",
|
||||
"ssl_score": "SSL-score"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Vastgemaakt door {author}",
|
||||
"user_disabled": "Reacties zijn uitgeschakeld in de instellingen.",
|
||||
"loading": "Reacties laden...",
|
||||
"disabled": "Reacties zijn uitgeschakeld door de uploader."
|
||||
"user_disabled": "Opmerkingen zijn uitgeschakeld in de instellingen.",
|
||||
"loading": "Opmerkingen laden…",
|
||||
"disabled": "Opmerkingen zijn uitgeschakeld door de uploader."
|
||||
},
|
||||
"info": {
|
||||
"preferences_note": "Let op: voorkeuren worden opgeslagen in de lokale opslag van uw browser. Als u uw browsergegevens verwijdert, worden ze opnieuw ingesteld.",
|
||||
"copied": "Gekopieerd!",
|
||||
"cannot_copy": "Kan niet kopiëren!",
|
||||
"page_not_found": "Pagina niet gevonden",
|
||||
"local_storage": "Deze actie vereist lokale opslag, zijn cookies ingeschakeld?"
|
||||
"local_storage": "Deze actie vereist lokale opslag, zijn cookies ingeschakeld?",
|
||||
"register_no_email_note": "Een e-mailadres als gebruikersnaam gebruiken wordt afgeraden. Toch doorgaan?",
|
||||
"next_video_countdown": "Volgende video wordt afgespeeld over {0}s",
|
||||
"days": "{amount} dag(en)",
|
||||
"weeks": "{amount} week/weken",
|
||||
"months": "{amount} maand(en)",
|
||||
"hours": "{amount} uur"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Geabonneerd op: {0}"
|
||||
|
210
src/locales/oc.json
Normal file
210
src/locales/oc.json
Normal file
@ -0,0 +1,210 @@
|
||||
{
|
||||
"titles": {
|
||||
"login": "Se connectar",
|
||||
"feed": "Flux",
|
||||
"preferences": "Preferéncias",
|
||||
"history": "Istoric",
|
||||
"account": "Compte",
|
||||
"instance": "Instància",
|
||||
"player": "Lector",
|
||||
"livestreams": "Dirèctes",
|
||||
"channels": "Canals",
|
||||
"trending": "Tendéncias",
|
||||
"register": "S’inscriure",
|
||||
"subscriptions": "Abonaments",
|
||||
"playlists": "Listas de lecturas",
|
||||
"bookmarks": "Marcapaginas",
|
||||
"channel_groups": "Grops de cadenas",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Agachar sus {0}"
|
||||
},
|
||||
"actions": {
|
||||
"subscribe": "S’abonar - {count}",
|
||||
"unsubscribe": "Se desabonar - {count}",
|
||||
"view_subscriptions": "Veire los abonaments",
|
||||
"sort_by": "Triar per :",
|
||||
"most_recent": "Mai recents",
|
||||
"least_recent": "Mens recents",
|
||||
"channel_name_asc": "Nom del canal (A-Z)",
|
||||
"channel_name_desc": "Nom del canal (Z-A)",
|
||||
"back": "Tornar",
|
||||
"skip_outro": "Passar los crèdits a la fin",
|
||||
"skip_preview": "Passar l’apercebut / resumit",
|
||||
"uses_api_from": "Utiliza l’API de ",
|
||||
"skip_intro": "Passar l’animacion d’entracte / Introduccion",
|
||||
"enable_sponsorblock": "Activar Sponsorblock",
|
||||
"skip_sponsors": "Passar las promocions",
|
||||
"show_comments": "Mostrar los comentaris",
|
||||
"minimize_description": "Minimizar la descripcion",
|
||||
"show_description": "Mostrar la descripcion",
|
||||
"show_recommendations": "Mostrar las recomandacions",
|
||||
"minimize_recommendations": "Minimizar las recomandacions",
|
||||
"enable_lbry_proxy": "Activar lo servidor mandatari per LBRY",
|
||||
"view_ssl_score": "Mostrar l’avaloracion SSL",
|
||||
"search": "Recercar (Ctrl+K)",
|
||||
"filter": "Filtrar",
|
||||
"disable_lbry": "Desactivar LBRY per la difusion en dirècte",
|
||||
"loading": "Cargament…",
|
||||
"clear_history": "Netejar l’istoric",
|
||||
"hide_replies": "Rescondre las responsas",
|
||||
"load_more_replies": "Cargar mai de responsas",
|
||||
"remove_from_playlist": "Levar de la lista de lectura",
|
||||
"add_to_playlist": "Apondre a la listra de lectura",
|
||||
"minimize_comments": "Minimizar los comentaris",
|
||||
"theme": "Tèma",
|
||||
"language_selection": "Lenga",
|
||||
"loop_this_video": "Legir en bocla la vidèo",
|
||||
"reset_preferences": "Restablir las preferéncias",
|
||||
"auto": "Auto",
|
||||
"dark": "Escur",
|
||||
"light": "Clar",
|
||||
"donations": "Don pel desvolopament",
|
||||
"backup_preferences": "Salvagardar las preferéncias",
|
||||
"share": "Partejar",
|
||||
"documentation": "Documentacion",
|
||||
"source_code": "Còdi font",
|
||||
"restore_preferences": "Restablir las preferéncias",
|
||||
"skip_interaction": "Ignorar los rapèls d’interaccion (S’abonar)",
|
||||
"show_markers": "Mostrar los marcadors sul lector",
|
||||
"default_quality": "Qualitat per defaut",
|
||||
"buffering_goal": "Objectiu de mesa en memòria tampon (en segondas)",
|
||||
"minimize_description_default": "Minimizar la descripcion per defaut",
|
||||
"instances_list": "Lista d’instàncias",
|
||||
"enabled_codecs": "Codecs activats (multiples)",
|
||||
"yes": "Òc",
|
||||
"no": "Non",
|
||||
"export_to_json": "Exportar en JSON",
|
||||
"import_from_json": "Importar d’un JSON",
|
||||
"auto_play_next_video": "Legir la vidèo seguenta automaticament",
|
||||
"create_playlist": "Crear una lista de lectura",
|
||||
"delete_playlist": "Levar de la lista de lectura",
|
||||
"select_playlist": "Seleccionatz una lista de lectura",
|
||||
"delete_playlist_confirm": "Suprimir aquesta lista de lectura ?",
|
||||
"clone_playlist": "Clonar la lista de lectura",
|
||||
"instance_auth_selection": "Instància d’autentificacion",
|
||||
"clone_playlist_success": "Clonatge capitat !",
|
||||
"follow_link": "Dobrir lo ligam",
|
||||
"skip_self_promo": "Sautar la promocion gratuita / autopromocion",
|
||||
"skip_non_music": "Sautar la musica : seccion non musicala",
|
||||
"skip_highlight": "Ignorar los tempses fòrts",
|
||||
"skip_filler_tangent": "Sautar la tangenta d’emplenament",
|
||||
"autoplay_video": "Legir automaticament la vidèo",
|
||||
"audio_only": "Sonque àudio",
|
||||
"minimize_comments_default": "Minimizar los comentaris per defaut",
|
||||
"instance_selection": "Instància",
|
||||
"please_select_playlist": "Seleccionatz una lista de lectura",
|
||||
"show_watch_on_youtube": "Mostrar lo boton « Veire sus YouTube »",
|
||||
"invalidate_session": "Se desconnectar de totes los aparelhs",
|
||||
"different_auth_instance": "Utilizar una instància diferenta per l’autentificacion",
|
||||
"back_to_home": "Tornar a l’acuèlh",
|
||||
"with_timecode": "Partejar amb còdi orari",
|
||||
"piped_link": "Ligam cap a Piped",
|
||||
"show_chapters": "Capítols",
|
||||
"country_selection": "País",
|
||||
"default_homepage": "Pagina d’acuèlh per defaut",
|
||||
"minimize_recommendations_default": "Minimizar las recomandacions per defaut",
|
||||
"store_watch_history": "Servar l’istoric de visualizacion",
|
||||
"show_more": "Ne mostrar mai",
|
||||
"delete_playlist_video_confirm": "Levar aquesta vidèo de la lista de lectura ?",
|
||||
"delete_account": "Suprimir lo compte",
|
||||
"logout": "Se desconnectar d’aqueste aparelh",
|
||||
"minimize_chapters_default": "Minimizar los capítols per defaut",
|
||||
"download_as_txt": "Telecargar coma .txt",
|
||||
"copy_link": "Copiar lo ligam",
|
||||
"time_code": "Moment (en segondas)",
|
||||
"store_search_history": "Gardar l’istoric de recèrca",
|
||||
"confirm_reset_preferences": "Volètz vertadièrament reïnicializar las preferéncias ?",
|
||||
"hide_watched": "Rescondre las vidèos vistas al flux",
|
||||
"reply_count": "{count} responsas",
|
||||
"with_playlist": "Partejar amb una lista de lectura",
|
||||
"playlist_bookmarked": "Marcat",
|
||||
"bookmark_playlist": "Marcapagina",
|
||||
"status_page": "Estat",
|
||||
"no_valid_playlists": "Lo fichièr conten pas cap de lista de lectura valida !",
|
||||
"instance_donations": "Dons d’instància",
|
||||
"skip_button_only": "Afichar lo boton per sautar",
|
||||
"skip_automatically": "Automaticament",
|
||||
"min_segment_length": "Durada minimum de segment (en segondas)",
|
||||
"skip_segment": "Sautar lo segment",
|
||||
"show_less": "Ne mostrar mens",
|
||||
"autoplay_next_countdown": "Descompte per defaut abans de passar a la vidèo seguenta (en segondas)",
|
||||
"dismiss": "Ignorar",
|
||||
"create_group": "Crear un grop",
|
||||
"group_name": "Nom del grop",
|
||||
"cancel": "Anullar",
|
||||
"okay": "D’acòrd",
|
||||
"edit_playlist": "Modificar la lista de lectura",
|
||||
"playlist_name": "Nom de la lista de lectura",
|
||||
"playlist_description": "Descripcion de la lista de lectura",
|
||||
"auto_display_captions": "Afichatge auto dels sostítols",
|
||||
"show_search_suggestions": "Mostrar las suggestions de recèrcas",
|
||||
"chapters_layout_mobile": "Disposicion capítols sus mobil",
|
||||
"enable_dearrow": "Activar DeArrow",
|
||||
"import_from_json_csv": "Importar d’un JSON/CSV"
|
||||
},
|
||||
"preferences": {
|
||||
"instance_locations": "Localizacion de l’instància",
|
||||
"registered_users": "Utilizaires inscriches",
|
||||
"instance_name": "Nom de l’instància",
|
||||
"has_cdn": "A un CDN ?",
|
||||
"version": "Version",
|
||||
"up_to_date": "Actualizat ?",
|
||||
"ssl_score": "Marca SSL"
|
||||
},
|
||||
"login": {
|
||||
"username": "Nom d’utilizaire",
|
||||
"password": "Senhal"
|
||||
},
|
||||
"video": {
|
||||
"views": "{views} visualizacions",
|
||||
"watched": "Vista",
|
||||
"ratings_disabled": "Avaloracions desactivadas",
|
||||
"sponsor_segments": "Segments de sponsors",
|
||||
"live": "{0} en dirècte",
|
||||
"shorts": "Corts",
|
||||
"chapters": "Capítols",
|
||||
"videos": "Vidèos",
|
||||
"all": "Totas",
|
||||
"category": "Categoria",
|
||||
"chapters_horizontal": "Orizontal",
|
||||
"chapters_vertical": "Vertical",
|
||||
"license": "Licéncia",
|
||||
"visibility": "Visibilitat"
|
||||
},
|
||||
"info": {
|
||||
"preferences_note": "Nòta : las preferéncias son gardadas dins l’espaci d’emmagazinatge del navegador. La supression de las donadas del navegador las restablirà.",
|
||||
"copied": "Copiat !",
|
||||
"page_not_found": "Pagina pas trobada",
|
||||
"cannot_copy": "Còpia impossibla !",
|
||||
"local_storage": "Aquesta accion requerís lo localStorage, son activats los cookies ?",
|
||||
"register_no_email_note": "Es pas recomandat d’utilizar una adreça electronica coma nom d’utilizaire. Contunhar çaquelà ?",
|
||||
"next_video_countdown": "La vidèo seguenta començarà d’aquí {0}s",
|
||||
"hours": "{amount} ora(s)",
|
||||
"months": "{amount} mes(es)",
|
||||
"days": "{amount} jorn(s)",
|
||||
"weeks": "{amount} setmana(s)"
|
||||
},
|
||||
"comment": {
|
||||
"disabled": "L’autor a desactivat los comentaris.",
|
||||
"loading": "Cargament dels comentaris…",
|
||||
"user_disabled": "Los comentaris son desactivats als paramètres.",
|
||||
"pinned_by": "Penjat per {author}"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Voliatz dire : {0} ?",
|
||||
"channels": "YouTube : Canals",
|
||||
"videos": "YouTube : Vidèos",
|
||||
"all": "YouTube : Tot",
|
||||
"playlists": "YouTube : Listas de lectura",
|
||||
"music_songs": "YT Music : Cançons",
|
||||
"music_videos": "YT Music : Vidèos",
|
||||
"music_albums": "YT Music : Albums",
|
||||
"music_playlists": "YT Music : Listas de lectura",
|
||||
"music_artists": "YT Music : Artistas"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Abonat a : {0}"
|
||||
}
|
||||
}
|
@ -12,7 +12,10 @@
|
||||
"account": "ଆକାଉଣ୍ଟ",
|
||||
"player": "ପ୍ଲେୟାର",
|
||||
"livestreams": "ସିଧାପ୍ରସାରଣ ଗୁଡ଼ିକ",
|
||||
"channels": "ସ୍ରୋତ ଗୁଡ଼ିକ"
|
||||
"channels": "ସ୍ରୋତ ଗୁଡ଼ିକ",
|
||||
"bookmarks": "ବୁକମାର୍କଗୁଡିକ",
|
||||
"channel_groups": "ଚ୍ୟାନେଲ୍ ଗୋଷ୍ଠୀଗୁଡିକ",
|
||||
"dearrow": "ଡି ତୀର"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "{0} ରେ ଦେଖନ୍ତୁ"
|
||||
@ -32,9 +35,7 @@
|
||||
"minimize_recommendations": "ସୁପାରିଶକୁ କମ୍ କରନ୍ତୁ",
|
||||
"show_recommendations": "ସୁପାରିଶଗୁଡିକ ଦେଖାନ୍ତୁ",
|
||||
"disable_lbry": "ଷ୍ଟ୍ରିମିଂ ପାଇଁ LBRY ଅକ୍ଷମ କରନ୍ତୁ",
|
||||
"search": "ସନ୍ଧାନ କରନ୍ତୁ",
|
||||
"rename_playlist": "ପ୍ଲେ ଲିଷ୍ଟର ନାମ ପରିବର୍ତ୍ତନ କରନ୍ତୁ",
|
||||
"new_playlist_name": "ନୂତନ ପ୍ଲେଲିଷ୍ଟ ନାମ",
|
||||
"search": "ସନ୍ଧାନ କରନ୍ତୁ (Ctrl+K)",
|
||||
"channel_name_asc": "ସ୍ରୋତ ର ନାମ (A-Z)",
|
||||
"least_recent": "ସର୍ବନିମ୍ନ ସାମ୍ପ୍ରତିକ",
|
||||
"channel_name_desc": "ସ୍ରୋତ ର ନାମ (Z-A)",
|
||||
@ -57,14 +58,14 @@
|
||||
"autoplay_video": "ଅଟୋପ୍ଲେ ଭିଡିଓ",
|
||||
"enabled_codecs": "ସକ୍ଷମ କୋଡେକସ୍ (ଏକାଧିକ)",
|
||||
"audio_only": "କେବଳ ସ୍ୱର",
|
||||
"language_selection": "ଭାଷା ଚୟନ",
|
||||
"language_selection": "ଭାଷା",
|
||||
"show_more": "ଅଧିକ ଦେଖାନ୍ତୁ",
|
||||
"buffering_goal": "ବଫରିଂ ଲକ୍ଷ୍ୟ (ସେକେଣ୍ଡରେ)",
|
||||
"country_selection": "ଦେଶ ଚୟନ",
|
||||
"country_selection": "ଦେଶ",
|
||||
"minimize_description_default": "ଡିଫଲ୍ଟ ଭାବରେ ବର୍ଣ୍ଣନାକୁ କମ୍ କରନ୍ତୁ",
|
||||
"store_watch_history": "ଦେଖିଥିବା ଭିଡିଓ ଗୁଡ଼ିକର ଇତିହାସ ରଖନ୍ତୁ",
|
||||
"instances_list": "ଉଦାହରଣ ତାଲିକା",
|
||||
"instance_selection": "ଇନଷ୍ଟାନ୍ସ ଚୟନ",
|
||||
"instance_selection": "ଇନଷ୍ଟାନ୍ସ",
|
||||
"yes": "ହଁ",
|
||||
"import_from_json": "JSON / CSV ରୁ ଆମଦାନୀ କରନ୍ତୁ",
|
||||
"no": "ନାହିଁ",
|
||||
@ -98,7 +99,7 @@
|
||||
"minimize_recommendations_default": "ଡିଫଲ୍ଟ ଭାବରେ ସୁପାରିଶକୁ କମ୍ କରନ୍ତୁ",
|
||||
"invalidate_session": "ସମସ୍ତ ଡିଭାଇସ୍ ରୁ ଲଗଆଉଟ୍ କରନ୍ତୁ",
|
||||
"download_as_txt": ".Txt ଭାବରେ ଡାଉନଲୋଡ୍ କରନ୍ତୁ",
|
||||
"instance_auth_selection": "ପ୍ରାମାଣିକିକରଣ ଇନଷ୍ଟାନ୍ସ ଚୟନ",
|
||||
"instance_auth_selection": "ପ୍ରାମାଣିକିକରଣ ଇନଷ୍ଟାନ୍ସ",
|
||||
"confirm_reset_preferences": "ଆପଣ ନିଶ୍ଚିତ କି ଆପଣ ଆପଣଙ୍କର ପସନ୍ଦଗୁଡିକ ପୁନଃ ସେଟ୍ କରିବାକୁ ଚାହୁଁଛନ୍ତି?",
|
||||
"status_page": "ସ୍ଥିତି",
|
||||
"different_auth_instance": "ପ୍ରାମାଣିକିକରଣ ପାଇଁ ଏକ ଭିନ୍ନ ଉଦାହରଣ ବ୍ୟବହାର କରନ୍ତୁ",
|
||||
@ -119,7 +120,30 @@
|
||||
"documentation": "ଡକ୍ୟୁମେଣ୍ଟେସନ୍",
|
||||
"instance_donations": "ଇନଷ୍ଟାଣ୍ଟ ଦାନ ଗୁଡ଼ିକ",
|
||||
"minimize_chapters_default": "ଡିଫଲ୍ଟ ଭାବରେ ଅଧ୍ୟାୟଗୁଡ଼ିକୁ କମ୍ କରନ୍ତୁ",
|
||||
"no_valid_playlists": "ଫାଇଲ୍ ଟି ବୈଧ ପ୍ଲେଲିଷ୍ଟ ଧାରଣ କରେ ନାହିଁ!"
|
||||
"no_valid_playlists": "ଫାଇଲ୍ ଟି ବୈଧ ପ୍ଲେଲିଷ୍ଟ ଧାରଣ କରେ ନାହିଁ!",
|
||||
"with_playlist": "ପ୍ଲେଲିଷ୍ଟ ସହିତ ଅଂଶୀଦାର କରନ୍ତୁ",
|
||||
"bookmark_playlist": "ବୁକମାର୍କ",
|
||||
"playlist_bookmarked": "ବୁକମାର୍କ ହୋଇଛି",
|
||||
"min_segment_length": "ସର୍ବନିମ୍ନ ସେଗମେଣ୍ଟ ଲମ୍ବ (ସେକେଣ୍ଡରେ)",
|
||||
"skip_button_only": "ସ୍କିପ୍ ବଟନ୍ ଦେଖାନ୍ତୁ",
|
||||
"skip_automatically": "ସ୍ୱୟଂଚାଳିତ ଭାବରେ",
|
||||
"skip_segment": "ସେଗମେଣ୍ଟକୁ ଏଡ଼ାଇଦିଅ",
|
||||
"show_less": "କମ୍ ଦେଖାନ୍ତୁ",
|
||||
"autoplay_next_countdown": "ପରବର୍ତ୍ତୀ ଭିଡିଓ ପର୍ଯ୍ୟନ୍ତ ଡିଫଲ୍ଟ କାଉଣ୍ଟଡାଉନ୍ (ସେକେଣ୍ଡରେ)",
|
||||
"dismiss": "ବରଖାସ୍ତ",
|
||||
"create_group": "ଗୋଷ୍ଠୀ ସୃଷ୍ଟି କରନ୍ତୁ",
|
||||
"group_name": "ଗୋଷ୍ଠୀ ନାମ",
|
||||
"enable_dearrow": "DeArrow କୁ ସକ୍ରିୟ କରନ୍ତୁ",
|
||||
"show_search_suggestions": "ସନ୍ଧାନ ପ୍ରସ୍ତାବଗୁଡ଼ିକୁ ଦର୍ଶାନ୍ତୁ",
|
||||
"delete_automatically": "ଏହା ପରେ ସ୍ୱୟଂଚାଳିତ ଭାବରେ ଅପସାରଣ କରନ୍ତୁ",
|
||||
"okay": "ଠିକ୍ ଅଛି",
|
||||
"edit_playlist": "ପ୍ଲେଲିଷ୍ଟକୁ ସମ୍ପାଦନ କରନ୍ତୁ",
|
||||
"playlist_name": "ପ୍ଲେ-ଲିଷ୍ଟ ନାମ",
|
||||
"generate_qrcode": "QR କୋଡ ସୃଷ୍ଟି କରନ୍ତୁ",
|
||||
"chapters_layout_mobile": "ମୋବାଇଲରେ ଅଧ୍ୟାୟ ବିନ୍ୟାସ",
|
||||
"auto_display_captions": "ଶୀର୍ଷକଗୁଡ଼ିକୁ ସ୍ୱୟଂଚାଳିତ ଭାବରେ ଦର୍ଶାନ୍ତୁ",
|
||||
"playlist_description": "ପ୍ଲେଲିଷ୍ଟ ବର୍ଣ୍ଣନା",
|
||||
"cancel": "ବାତିଲ କରନ୍ତୁ"
|
||||
},
|
||||
"comment": {
|
||||
"loading": "ମନ୍ତବ୍ୟ ଲୋଡ୍ ହେଉଛି ...",
|
||||
@ -135,7 +159,13 @@
|
||||
"videos": "ଭିଡିଓ ଗୁଡିକ",
|
||||
"ratings_disabled": "ମୂଲ୍ୟାୟନ ଅକ୍ଷମ ହୋଇଛି",
|
||||
"chapters": "ଅଧ୍ୟାୟ ଗୁଡ଼ିକ",
|
||||
"live": "{0} ସିଧାପ୍ରସାରଣ"
|
||||
"live": "{0} ସିଧାପ୍ରସାରଣ",
|
||||
"all": "ସମସ୍ତ",
|
||||
"category": "ବର୍ଗ",
|
||||
"visibility": "ଦୃଶ୍ୟମାନତା",
|
||||
"license": "ଲାଇସେନ୍ସ",
|
||||
"chapters_horizontal": "ଭୂସମାନ୍ତର",
|
||||
"chapters_vertical": "ଭୂଲମ୍ବ"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "ଆପଣ କହିବାକୁ ଚାହୁଁଛନ୍ତି କି: {0}?",
|
||||
@ -146,7 +176,8 @@
|
||||
"videos": "ୟୁଟ୍ୟୁବ୍: ଭିଡିଓଗୁଡିକ",
|
||||
"channels": "ୟୁଟ୍ୟୁବ୍: ଚ୍ୟାନେଲଗୁଡିକ",
|
||||
"music_songs": "ୟୁଟିଉବ୍ ସଙ୍ଗୀତ: ଗୀତ ଗୁଡ଼ିକ",
|
||||
"playlists": "ୟୁଟ୍ୟୁବ୍: ପ୍ଲେଲିଷ୍ଟଗୁଡିକ"
|
||||
"playlists": "ୟୁଟ୍ୟୁବ୍: ପ୍ଲେଲିଷ୍ଟଗୁଡିକ",
|
||||
"music_artists": "ୱାଇଟି ମ୍ୟୁଜିକ: ଆର୍ଟିଷ୍ଟ"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "ସଦସ୍ୟତା: {0}"
|
||||
@ -156,7 +187,13 @@
|
||||
"copied": "କପି ହୋଇଛି!",
|
||||
"cannot_copy": "କପି କରିପାରିବ ନାହିଁ!",
|
||||
"page_not_found": "ପୃଷ୍ଠାଟି ମିଳିଲା ନାହିଁ",
|
||||
"local_storage": "ଏହି କ୍ରିୟା ଲୋକାଲ୍ ଷ୍ଟୋରେଜ୍ ଆବଶ୍ୟକ କରେ, କୁକିଜ୍ ସକ୍ଷମ ଅଛି କି?"
|
||||
"local_storage": "ଏହି କ୍ରିୟା ଲୋକାଲ୍ ଷ୍ଟୋରେଜ୍ ଆବଶ୍ୟକ କରେ, କୁକିଜ୍ ସକ୍ଷମ ଅଛି କି?",
|
||||
"register_no_email_note": "ଉପଯୋଗକର୍ତ୍ତା ନାମ ଭାବରେ ଏକ ଇ-ମେଲ୍ ବ୍ୟବହାର କରିବା ସୁପାରିଶ କରାଯାଏ ନାହିଁ । ଯେକୌଣସି ପ୍ରକାରେ ଅଗ୍ରଗତି କରନ୍ତୁ?",
|
||||
"next_video_countdown": "{0} ସେକେଣ୍ଡ ରେ ପରବର୍ତ୍ତୀ ଭିଡିଓ ଖେଳିବାକୁ ଆରମ୍ଭ ହେବ",
|
||||
"hours": "{amount} ଘଣ୍ଟା",
|
||||
"days": "{amount} ଦିନ",
|
||||
"weeks": "{amount} ସପ୍ତାହ",
|
||||
"months": "{amount} ମାସ"
|
||||
},
|
||||
"preferences": {
|
||||
"instance_name": "ଇନଷ୍ଟାନ୍ସ ନାମ",
|
||||
@ -169,6 +206,8 @@
|
||||
},
|
||||
"login": {
|
||||
"password": "ପାସୱାର୍ଡ",
|
||||
"username": "ଉପଯୋଗକର୍ତ୍ତା ନାମ"
|
||||
"username": "ଉପଯୋଗକର୍ତ୍ତା ନାମ",
|
||||
"passwords_incorrect": "ପ୍ରବେଶ ସଂକେତ ମେଳ ଖାଉନାହିଁ!",
|
||||
"password_confirm": "ପ୍ରବେଶ ସଂକେତ ନିଶ୍ଚିତ କରନ୍ତୁ"
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,14 @@
|
||||
"account": "Konto",
|
||||
"instance": "Instancja",
|
||||
"livestreams": "Na żywo",
|
||||
"channels": "Kanały"
|
||||
"channels": "Kanały",
|
||||
"bookmarks": "Zakładki",
|
||||
"channel_groups": "Grupy kanałów",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Obejrzyj na {0}"
|
||||
"watch_on": "Obejrzyj na {0}",
|
||||
"failed": "Niepowodzenie z powodu kodu błędu {0}, przejrzyj logi, aby uzyskać więcej informacji"
|
||||
},
|
||||
"actions": {
|
||||
"subscribe": "Subskrybuj - {count}",
|
||||
@ -46,20 +50,20 @@
|
||||
"audio_only": "Tylko audio",
|
||||
"default_quality": "Domyślna jakość",
|
||||
"buffering_goal": "Cel buforowania (w sekundach)",
|
||||
"country_selection": "Wybór kraju",
|
||||
"country_selection": "Kraj",
|
||||
"default_homepage": "Domyślna strona główna",
|
||||
"show_comments": "Pokaż komentarze",
|
||||
"minimize_description_default": "Ukryj opis",
|
||||
"store_watch_history": "Zapamiętaj historię oglądania",
|
||||
"language_selection": "Wybór języka",
|
||||
"language_selection": "Język",
|
||||
"instances_list": "Lista instancji",
|
||||
"enabled_codecs": "Włączone kodeki (lista wielokrotnego wyboru)",
|
||||
"instance_selection": "Wybór instancji",
|
||||
"instance_selection": "Instancja",
|
||||
"show_more": "Pokaż więcej",
|
||||
"yes": "Tak",
|
||||
"no": "Nie",
|
||||
"export_to_json": "Eksport do pliku JSON",
|
||||
"import_from_json": "Import z pliku JSON/CSV",
|
||||
"import_from_json": "Import z pliku JSON",
|
||||
"loop_this_video": "Zapętlaj ten film",
|
||||
"auto_play_next_video": "Autoodtwarzanie następnego filmu",
|
||||
"donations": "Wsparcie",
|
||||
@ -67,10 +71,10 @@
|
||||
"show_description": "Pokaż opis",
|
||||
"minimize_recommendations": "Ukryj proponowane",
|
||||
"show_recommendations": "Pokaż proponowane",
|
||||
"disable_lbry": "Wyłącz LBRY dla streaming-u",
|
||||
"disable_lbry": "Wyłącz LBRY dla przesyłania strumieniowego",
|
||||
"enable_lbry_proxy": "Włącz proxy dla LBRY",
|
||||
"view_ssl_score": "Pokaż ocenę SSL",
|
||||
"search": "Szukaj",
|
||||
"search": "Szukaj (Ctrl+K)",
|
||||
"filter": "Filtruj",
|
||||
"loading": "Ładowanie...",
|
||||
"clear_history": "Wyczyść historię",
|
||||
@ -92,7 +96,7 @@
|
||||
"documentation": "Dokumentacja",
|
||||
"instance_donations": "Darowizny na rzecz instancji",
|
||||
"back_to_home": "Idź do strony głównej",
|
||||
"instance_auth_selection": "Wybrana instancja autoryzacyjna",
|
||||
"instance_auth_selection": "Instancja uwierzytelniania",
|
||||
"time_code": "Kod czasowy (w sekundach)",
|
||||
"show_markers": "Pokaż segmenty na odtwarzaczu",
|
||||
"store_search_history": "Zapamiętaj historię wyszukiwania",
|
||||
@ -100,7 +104,6 @@
|
||||
"source_code": "Kod źródłowy",
|
||||
"show_chapters": "Rozdziały",
|
||||
"minimize_chapters_default": "Ukryj rozdziały",
|
||||
"rename_playlist": "Zmień nazwę playlisty",
|
||||
"follow_link": "Otwórz link",
|
||||
"minimize_comments_default": "Ukryj sekcję komentarzy",
|
||||
"minimize_comments": "Ukryj komentarze",
|
||||
@ -113,14 +116,37 @@
|
||||
"backup_preferences": "Pobierz kopię zapasową ustawień",
|
||||
"download_as_txt": "Pobierz jako .txt",
|
||||
"reset_preferences": "Zresetuj ustawienia",
|
||||
"new_playlist_name": "Nowa nazwa playlisty",
|
||||
"share": "Udostępnij",
|
||||
"with_timecode": "Udostępnij z kodem czasowym",
|
||||
"piped_link": "Link Piped",
|
||||
"status_page": "Status",
|
||||
"reply_count": "{count} odpowiedzi",
|
||||
"no_valid_playlists": "Ten plik nie zawiera poprawnych playlist!",
|
||||
"with_playlist": "Udostępnij z playlistą"
|
||||
"with_playlist": "Udostępnij z playlistą",
|
||||
"playlist_bookmarked": "Dodano do zakładek",
|
||||
"bookmark_playlist": "Zakładka",
|
||||
"skip_button_only": "Pokaż przycisk pomijania",
|
||||
"skip_automatically": "Automatycznie",
|
||||
"min_segment_length": "Minimalna długość segmentu (w sekundach)",
|
||||
"skip_segment": "Pomiń segment",
|
||||
"show_less": "Pokaż mniej",
|
||||
"autoplay_next_countdown": "Domyślne odliczanie do następnego filmu (w sekundach)",
|
||||
"dismiss": "Odrzuć",
|
||||
"group_name": "Nazwa grupy",
|
||||
"create_group": "Utwórz grupę",
|
||||
"auto_display_captions": "Automatyczne wyświetlanie napisów",
|
||||
"edit_playlist": "Edytuj playlistę",
|
||||
"playlist_name": "Nazwa playlisty",
|
||||
"playlist_description": "Opis playlisty",
|
||||
"okay": "OK",
|
||||
"cancel": "Anuluj",
|
||||
"show_search_suggestions": "Pokaż sugestie wyszukiwania",
|
||||
"chapters_layout_mobile": "Układ rozdziałów na urządzeniach mobilnych",
|
||||
"delete_automatically": "Usuń automatycznie po",
|
||||
"enable_dearrow": "Włącz DeArrow",
|
||||
"generate_qrcode": "Wygeneruj kod QR",
|
||||
"import_from_json_csv": "Import z pliku JSON/CSV",
|
||||
"download_frame": "Pobierz klatkę"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Przypięty przez {author}",
|
||||
@ -139,7 +165,9 @@
|
||||
},
|
||||
"login": {
|
||||
"username": "Nazwa użytkownika",
|
||||
"password": "Hasło"
|
||||
"password": "Hasło",
|
||||
"password_confirm": "Potwierdź hasło",
|
||||
"passwords_incorrect": "Hasła się nie zgadzają!"
|
||||
},
|
||||
"video": {
|
||||
"videos": "Filmy",
|
||||
@ -148,8 +176,14 @@
|
||||
"sponsor_segments": "Segmenty sponsorowane",
|
||||
"ratings_disabled": "Ocenianie wyłączone",
|
||||
"chapters": "Rozdziały",
|
||||
"live": "{0} Na żywo",
|
||||
"shorts": "Krótkie wideo"
|
||||
"live": "{0} na żywo",
|
||||
"shorts": "Krótkie wideo",
|
||||
"all": "Wszystkie",
|
||||
"category": "Kategoria",
|
||||
"chapters_horizontal": "Poziomy",
|
||||
"chapters_vertical": "Pionowy",
|
||||
"license": "Licencja",
|
||||
"visibility": "Widoczność"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Czy chodziło ci o: {0}?",
|
||||
@ -160,14 +194,21 @@
|
||||
"music_songs": "YT Music: Utwory",
|
||||
"music_videos": "YT Music: Teledyski",
|
||||
"music_albums": "YT Music: Albumy",
|
||||
"music_playlists": "YT Music: Playlisty"
|
||||
"music_playlists": "YT Music: Playlisty",
|
||||
"music_artists": "YT Music: Wykonawcy"
|
||||
},
|
||||
"info": {
|
||||
"cannot_copy": "Nie można skopiować!",
|
||||
"copied": "Skopiowano!",
|
||||
"page_not_found": "Strona nie znaleziona",
|
||||
"preferences_note": "Uwaga: ustawienia są zapisywane w lokalnej pamięci przeglądarki. Usunięcie danych przeglądarki spowoduje ich zresetowanie.",
|
||||
"local_storage": "Ta akcja wymaga dostępu do lokalnej pamięci, czy pliki cookie są włączone?"
|
||||
"local_storage": "Ta akcja wymaga dostępu do lokalnej pamięci, czy pliki cookie są włączone?",
|
||||
"register_no_email_note": "Użycie adresu email jako nazwy użytkownika jest niezalecane. Kontynuować mimo to?",
|
||||
"next_video_countdown": "Odtwarzanie następnego filmu za {0} s",
|
||||
"days": "{amount} dni",
|
||||
"weeks": "{amount} tygodnie",
|
||||
"hours": "{amount} godziny",
|
||||
"months": "{amount} miesiące"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Licznik subskrybcji: {0}"
|
||||
|
@ -1,174 +1,216 @@
|
||||
{
|
||||
"titles": {
|
||||
"trending": "Tendências",
|
||||
"preferences": "Configurações",
|
||||
"preferences": "Preferências",
|
||||
"subscriptions": "Subscrições",
|
||||
"login": "Iniciar Sessão",
|
||||
"login": "Iniciar sessão",
|
||||
"register": "Registar",
|
||||
"history": "Histórico",
|
||||
"feed": "Conteúdo",
|
||||
"playlists": "Listas de Reprodução",
|
||||
"playlists": "Listas de reprodução",
|
||||
"account": "Conta",
|
||||
"instance": "Instância",
|
||||
"player": "Reprodutor",
|
||||
"livestreams": "Transmissões ao vivo",
|
||||
"channels": "Canais"
|
||||
"livestreams": "Emissões em direto",
|
||||
"channels": "Canais",
|
||||
"bookmarks": "Marcadores",
|
||||
"channel_groups": "Grupos de canais",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"actions": {
|
||||
"sort_by": "Ordenar por:",
|
||||
"most_recent": "Mais Recente",
|
||||
"least_recent": "Menos Recente",
|
||||
"channel_name_asc": "Nome do Canal (A-Z)",
|
||||
"back": "Voltar",
|
||||
"most_recent": "Mais recentes",
|
||||
"least_recent": "Mais antigos",
|
||||
"channel_name_asc": "Nome do canal (A-Z)",
|
||||
"back": "Recuar",
|
||||
"uses_api_from": "Utiliza a \"API\" de ",
|
||||
"enable_sponsorblock": "Ativar \"SponsorBlock\"",
|
||||
"skip_intro": "Saltar Intermissão/Animação de Introdução",
|
||||
"skip_outro": "Saltar \"Endcards\"/Créditos",
|
||||
"skip_preview": "Saltar Pré-Visualização/Recapitulação",
|
||||
"skip_intro": "Ignorar intermissão/animação de introdução",
|
||||
"skip_outro": "Ignorar \"Endcards\"/Créditos",
|
||||
"skip_preview": "Ignorar pré-visualização/recapitulando",
|
||||
"auto": "Automático",
|
||||
"dark": "Escuro",
|
||||
"autoplay_video": "Reproduzir Vídeo Automaticamente",
|
||||
"audio_only": "Apenas Áudio",
|
||||
"default_quality": "Qualidade Padrão",
|
||||
"country_selection": "Seleção de País",
|
||||
"default_homepage": "Página Inicial Padrão",
|
||||
"show_comments": "Mostrar Comentários",
|
||||
"minimize_description_default": "Minimizar Descrição por defeito",
|
||||
"store_watch_history": "Guardar Histórico de Visualizações",
|
||||
"instances_list": "Lista de Instâncias",
|
||||
"enabled_codecs": "\"Codecs\" Activados (Vários)",
|
||||
"instance_selection": "Seleção de Instância",
|
||||
"show_more": "Mostrar Mais",
|
||||
"import_from_json": "Importar de JSON/CSV",
|
||||
"autoplay_video": "Reproduzir vídeos automaticamente",
|
||||
"audio_only": "Apenas áudio",
|
||||
"default_quality": "Qualidade padrão",
|
||||
"country_selection": "País",
|
||||
"default_homepage": "Página inicial padrão",
|
||||
"show_comments": "Mostrar comentários",
|
||||
"minimize_description_default": "Minimizar descrição por omissão",
|
||||
"store_watch_history": "Guardar histórico de visualizações",
|
||||
"instances_list": "Lista de instâncias",
|
||||
"enabled_codecs": "Codificadores ativados (vários)",
|
||||
"instance_selection": "Instância",
|
||||
"show_more": "Mostrar mais",
|
||||
"import_from_json": "Importar de JSON",
|
||||
"export_to_json": "Exportar para JSON",
|
||||
"loop_this_video": "Repetir este Vídeo",
|
||||
"auto_play_next_video": "Reproduzir Automaticamente o próximo Vídeo",
|
||||
"donations": "Doações de desenvolvimento",
|
||||
"minimize_description": "Minimizar Descrição",
|
||||
"show_description": "Mostrar Descrição",
|
||||
"show_recommendations": "Mostrar Recomendações",
|
||||
"disable_lbry": "Desactivar \"LBRY\" para Transmissão",
|
||||
"enable_lbry_proxy": "Activar \"Proxy\" para \"LBRY\"",
|
||||
"view_ssl_score": "Ver Pontuação \"SSL\"",
|
||||
"search": "Procurar",
|
||||
"loop_this_video": "Repetir este vídeo",
|
||||
"auto_play_next_video": "Reproduzir vídeo seguinte automaticamente",
|
||||
"donations": "Doações para o desenvolvimento",
|
||||
"minimize_description": "Minimizar descrição",
|
||||
"show_description": "Mostrar descrição",
|
||||
"show_recommendations": "Mostrar recomendações",
|
||||
"disable_lbry": "Desativar \"LBRY\" para emissões",
|
||||
"enable_lbry_proxy": "Ativar proxy para \"LBRY\"",
|
||||
"view_ssl_score": "Ver avaliação \"SSL\"",
|
||||
"search": "Pesquisa (Ctrl+K)",
|
||||
"filter": "Filtrar",
|
||||
"loading": "A Carregar...",
|
||||
"clear_history": "Limpar Histórico",
|
||||
"loading": "A carregar...",
|
||||
"clear_history": "Limpar histórico",
|
||||
"subscribe": "Subscrever - {count}",
|
||||
"unsubscribe": "Anular subscrição - {count}",
|
||||
"view_subscriptions": "Ver Subscrições",
|
||||
"channel_name_desc": "Nome do Canal (Z-A)",
|
||||
"skip_sponsors": "Saltar Patrocínios",
|
||||
"view_subscriptions": "Ver subscrições",
|
||||
"channel_name_desc": "Nome do canal (Z-A)",
|
||||
"skip_sponsors": "Ignorar patrocínios",
|
||||
"yes": "Sim",
|
||||
"skip_non_music": "Saltar Música: Secção Não-Musical",
|
||||
"skip_non_music": "Ignorar música: secção não musical",
|
||||
"no": "Não",
|
||||
"theme": "Tema",
|
||||
"language_selection": "Seleção de Idioma",
|
||||
"minimize_recommendations": "Minimizar Recomendações",
|
||||
"language_selection": "Idioma",
|
||||
"minimize_recommendations": "Minimizar recomendações",
|
||||
"light": "Claro",
|
||||
"hide_replies": "Ocultar Respostas",
|
||||
"load_more_replies": "Carregar mais Respostas",
|
||||
"skip_highlight": "Saltar Destaque",
|
||||
"skip_interaction": "Saltar Lembrete de Interação (Subscreve)",
|
||||
"skip_self_promo": "Saltar Promoção Não Paga/Auto-Promoção",
|
||||
"buffering_goal": "Objetivo de \"Buffering\" (em segundos)",
|
||||
"skip_filler_tangent": "Saltar Tangente \"Filler\"",
|
||||
"hide_replies": "Ocultar respostas",
|
||||
"load_more_replies": "Carregar mais respostas",
|
||||
"skip_highlight": "Ignorar destaques",
|
||||
"skip_interaction": "Ignorar lembrete de interação (subscrição)",
|
||||
"skip_self_promo": "Ignorar promoção gratuita/auto-promoção",
|
||||
"buffering_goal": "Objetivo de 'buffer' (em segundos)",
|
||||
"skip_filler_tangent": "Ignorar segmentos de preenchimento",
|
||||
"add_to_playlist": "Adicionar à lista de reprodução",
|
||||
"delete_playlist": "Apagar Lista de Reprodução",
|
||||
"select_playlist": "Selecionar uma Lista de Reprodução",
|
||||
"delete_playlist": "Apagar lista de reprodução",
|
||||
"select_playlist": "Selecionar uma lista de reprodução",
|
||||
"delete_playlist_confirm": "Apagar esta lista de reprodução?",
|
||||
"please_select_playlist": "Selecionar uma lista de reprodução se faz favor",
|
||||
"delete_playlist_video_confirm": "Remover o vídeo da lista de reprodução?",
|
||||
"please_select_playlist": "Selecione uma lista de reprodução",
|
||||
"delete_playlist_video_confirm": "Remover vídeo da lista de reprodução?",
|
||||
"remove_from_playlist": "Remover da lista de reprodução",
|
||||
"create_playlist": "Criar Lista de Reprodução",
|
||||
"create_playlist": "Criar lista de reprodução",
|
||||
"clone_playlist_success": "Clonada com sucesso!",
|
||||
"clone_playlist": "Clonar Lista de Reprodução",
|
||||
"show_markers": "Mostrar Marcadores no Leitor",
|
||||
"delete_account": "Apagar Conta",
|
||||
"logout": "Terminar sessão neste aparelho",
|
||||
"minimize_recommendations_default": "Minimizar Recomendações por defeito",
|
||||
"invalidate_session": "Terminar sessão em todos os aparelhos",
|
||||
"clone_playlist": "Clonar lista de reprodução",
|
||||
"show_markers": "Mostrar marcas no reprodutor",
|
||||
"delete_account": "Apagar conta",
|
||||
"logout": "Terminar sessão neste dispositivo",
|
||||
"minimize_recommendations_default": "Minimizar recomendações por omissão",
|
||||
"invalidate_session": "Terminar sessão em todos os dispositivos",
|
||||
"different_auth_instance": "Usar uma instância diferente para autenticação",
|
||||
"instance_auth_selection": "Selecção da Instância para Autenticação",
|
||||
"confirm_reset_preferences": "Tem a certeza que quer redefinir as suas configurações?",
|
||||
"instance_auth_selection": "Instância para autenticação",
|
||||
"confirm_reset_preferences": "Tem a certeza de que deseja repor as preferências?",
|
||||
"download_as_txt": "Descarregar como .txt",
|
||||
"reset_preferences": "Redefinir preferências",
|
||||
"restore_preferences": "Restaurar configurações",
|
||||
"reset_preferences": "Repor preferências",
|
||||
"restore_preferences": "Restaurar preferências",
|
||||
"follow_link": "Seguir ligação",
|
||||
"piped_link": "Ligação do Piped",
|
||||
"backup_preferences": "Exportar configurações",
|
||||
"store_search_history": "Armazenar Histórico de Pesquisa",
|
||||
"hide_watched": "Ocultar vídeos assistidos no feed",
|
||||
"backup_preferences": "Exportar preferências",
|
||||
"store_search_history": "Guardar histórico de pesquisas",
|
||||
"hide_watched": "Ocultar do feed os vídeos visualizados",
|
||||
"documentation": "Documentação",
|
||||
"status_page": "Estado",
|
||||
"source_code": "Código-fonte",
|
||||
"instance_donations": "Doações de instâncias",
|
||||
"minimize_chapters_default": "Minimizar Capítulos por padrão",
|
||||
"show_watch_on_youtube": "Mostrar Botão Assistir no YouTube",
|
||||
"new_playlist_name": "Novo nome da lista de reprodução",
|
||||
"minimize_comments": "Minimizar Comentários",
|
||||
"minimize_chapters_default": "Minimizar capítulos por omissão",
|
||||
"show_watch_on_youtube": "Mostrar botão Ver no YouTube",
|
||||
"minimize_comments": "Minimizar comentários",
|
||||
"back_to_home": "Voltar ao início",
|
||||
"rename_playlist": "Renomear",
|
||||
"copy_link": "Copiar ligação",
|
||||
"time_code": "Código de tempo (em segundos)",
|
||||
"minimize_comments_default": "Minimizar Comentários por defeito",
|
||||
"minimize_comments_default": "Minimizar comentários por omissão",
|
||||
"share": "Partilhar",
|
||||
"with_timecode": "Partilhar com código de tempo",
|
||||
"show_chapters": "Capítulos",
|
||||
"reply_count": "{count} respostas",
|
||||
"no_valid_playlists": "O ficheiro não contém listas de reprodução válidas!"
|
||||
"no_valid_playlists": "O ficheiro não contém listas de reprodução válidas!",
|
||||
"with_playlist": "Partilhar com lista de reprodução",
|
||||
"playlist_bookmarked": "Marcado",
|
||||
"bookmark_playlist": "Marcador",
|
||||
"skip_button_only": "Mostrar botão Ignorar",
|
||||
"skip_automatically": "Automaticamente",
|
||||
"min_segment_length": "Tamanho mínimo do segmento (segundos)",
|
||||
"skip_segment": "Ignorar segmento",
|
||||
"show_less": "Mostrar menos",
|
||||
"dismiss": "Ignorar",
|
||||
"autoplay_next_countdown": "Contagem decrescente até ao próximo vídeo (em segundos)",
|
||||
"create_group": "Criar grupo",
|
||||
"group_name": "Nome do grupo",
|
||||
"auto_display_captions": "Mostrar legendas",
|
||||
"playlist_description": "Descrição da lista de reprodução",
|
||||
"okay": "Ok",
|
||||
"cancel": "Cancelar",
|
||||
"edit_playlist": "Editar lista de reprodução",
|
||||
"playlist_name": "Nome da lista de reprodução",
|
||||
"show_search_suggestions": "Mostrar sugestões de pesquisa",
|
||||
"chapters_layout_mobile": "Aplicações recentemente adicionadas",
|
||||
"enable_dearrow": "Ativar o DeArrow",
|
||||
"delete_automatically": "Eliminar automaticamente após",
|
||||
"generate_qrcode": "Gerar código QR",
|
||||
"import_from_json_csv": "Importar de JSON/CSV",
|
||||
"download_frame": "Quadro de transferência"
|
||||
},
|
||||
"preferences": {
|
||||
"instance_name": "Nome da Instância",
|
||||
"instance_locations": "Localizações da Instância",
|
||||
"ssl_score": "Pontuação \"SSL\"",
|
||||
"has_cdn": "Tem \"CDN\"?",
|
||||
"instance_name": "Nome da instância",
|
||||
"instance_locations": "Localizações da instância",
|
||||
"ssl_score": "Avaliação SSL",
|
||||
"has_cdn": "Tem CDN?",
|
||||
"version": "Versão",
|
||||
"registered_users": "Utilizadores Registados",
|
||||
"registered_users": "Utilizadores registados",
|
||||
"up_to_date": "Atualizada?"
|
||||
},
|
||||
"login": {
|
||||
"password": "Palavra-passe",
|
||||
"username": "Nome de utilizador"
|
||||
"username": "Nome de utilizador",
|
||||
"passwords_incorrect": "As palavras-passe não coincidem!",
|
||||
"password_confirm": "Confirmar a palavra-passe"
|
||||
},
|
||||
"video": {
|
||||
"videos": "Vídeos",
|
||||
"views": "{views} visualizações",
|
||||
"watched": "Visto",
|
||||
"sponsor_segments": "Segmentos Patrocinados",
|
||||
"ratings_disabled": "Classificações Desactivadas",
|
||||
"sponsor_segments": "Segmentos patrocinados",
|
||||
"ratings_disabled": "Avaliações desativadas",
|
||||
"chapters": "Capítulos",
|
||||
"live": "{0} em Direto",
|
||||
"shorts": "\"Shorts\""
|
||||
"live": "{0} em direto",
|
||||
"shorts": "Curtos",
|
||||
"all": "Todos",
|
||||
"category": "Categoria",
|
||||
"chapters_horizontal": "Horizontal",
|
||||
"chapters_vertical": "Vertical",
|
||||
"license": "Licença",
|
||||
"visibility": "Visibilidade"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Será que querias dizer: {0}?",
|
||||
"did_you_mean": "Será que queria dizer: {0}?",
|
||||
"all": "YouTube: Tudo",
|
||||
"videos": "YouTube: Vídeos",
|
||||
"channels": "YouTube: Canais",
|
||||
"music_songs": "YT Music: Músicas",
|
||||
"music_videos": "YT Music: Vídeos",
|
||||
"music_albums": "YT Music: Álbuns",
|
||||
"music_playlists": "YT Music: Listas de Reprodução",
|
||||
"playlists": "YouTube: Listas de Reprodução"
|
||||
"music_playlists": "YT Music: Listas de reprodução",
|
||||
"playlists": "YouTube: Listas de reprodução",
|
||||
"music_artists": "YT Music: Artistas"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Ver em {0}"
|
||||
"watch_on": "Ver em {0}",
|
||||
"failed": "Falha com o código de erro {0}, ver registos para mais informações"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Afixado por {author}",
|
||||
"disabled": "Os comentários estão desactivados pelo dono do canal.",
|
||||
"disabled": "O dono do canal desativou os comentários.",
|
||||
"loading": "A carregar comentários...",
|
||||
"user_disabled": "Os comentários estão desactivados nas definições."
|
||||
"user_disabled": "Os comentários estão desativados nas definições."
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Subscrito a: {0}"
|
||||
"subscribed_channels_count": "Subscreveu: {0}"
|
||||
},
|
||||
"info": {
|
||||
"copied": "Copiada!",
|
||||
"cannot_copy": "Não foi possível copiar!",
|
||||
"page_not_found": "Página não encontrada",
|
||||
"local_storage": "Esta ação requer localStorage, os cookies estão ativados?",
|
||||
"preferences_note": "Nota: as configurações são guardadas no armazenamento local to seu navegador. Eliminar os dados de navegação irá redefini-las."
|
||||
"preferences_note": "Nota: as preferências são guardadas no armazenamento local do seu navegador. Se limpar os dados de navegação, também limpa as preferências.",
|
||||
"register_no_email_note": "Não recomendamos utilizar um endereço de e-mail como nome de utilizador. Continuar?",
|
||||
"next_video_countdown": "O próximo vídeo será reproduzido dentro de {0} segundos",
|
||||
"hours": "{quantidade} hora(s)",
|
||||
"days": "{quantidade} dia(s)",
|
||||
"weeks": "{quantidade} semana(s)",
|
||||
"months": "{quantidade} mês(es)"
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
"dark": "Escuro",
|
||||
"light": "Claro",
|
||||
"show_comments": "Exibir Comentários",
|
||||
"country_selection": "Seleção de País",
|
||||
"country_selection": "País",
|
||||
"default_homepage": "Página Inicial Padrão",
|
||||
"default_quality": "Qualidade Padrão",
|
||||
"autoplay_video": "Reprodução Automática",
|
||||
@ -34,7 +34,7 @@
|
||||
"skip_non_music": "Pular Música: Seção não Musical",
|
||||
"skip_filler_tangent": "Pular Enchimento Tangencial",
|
||||
"enabled_codecs": "Codecs Ativados (Múltiplos)",
|
||||
"language_selection": "Seleção de Idioma",
|
||||
"language_selection": "Idioma",
|
||||
"yes": "Sim",
|
||||
"show_more": "Mostrar Mais",
|
||||
"export_to_json": "Exportar para JSON",
|
||||
@ -55,14 +55,14 @@
|
||||
"view_ssl_score": "Ver Pontuação SSL",
|
||||
"disable_lbry": "Desativar LBRY para Streaming",
|
||||
"enable_lbry_proxy": "Ativar Proxy para LBRY",
|
||||
"import_from_json": "Importar de JSON/CSV",
|
||||
"import_from_json": "Importar de JSON",
|
||||
"loop_this_video": "Repetir este Vídeo",
|
||||
"instances_list": "Lista de Instâncias",
|
||||
"clear_history": "Limpar Histórico",
|
||||
"search": "Pesquisar",
|
||||
"search": "Pesquisar (Ctrl+K)",
|
||||
"no": "Não",
|
||||
"show_description": "Exibir Descrição",
|
||||
"instance_selection": "Seleção de Instância",
|
||||
"instance_selection": "Instância",
|
||||
"auto_play_next_video": "Autorreproduzir Próximo Vídeo",
|
||||
"filter": "Filtro",
|
||||
"store_watch_history": "Salvar Histórico de Exibição",
|
||||
@ -81,14 +81,12 @@
|
||||
"status_page": "Estado",
|
||||
"source_code": "Código fonte",
|
||||
"instance_donations": "Doações de instâncias",
|
||||
"instance_auth_selection": "Seleção de Instância de Autenticação",
|
||||
"instance_auth_selection": "Instância de Autenticação",
|
||||
"clone_playlist_success": "Clonada com sucesso!",
|
||||
"download_as_txt": "Baixar como .txt",
|
||||
"restore_preferences": "Restaurar preferências",
|
||||
"back_to_home": "Voltar ao início",
|
||||
"share": "Compartilhar",
|
||||
"rename_playlist": "Renomear playlist",
|
||||
"new_playlist_name": "Novo nome da playlist",
|
||||
"with_timecode": "Compartilhar com código de tempo",
|
||||
"piped_link": "Link do Piped",
|
||||
"follow_link": "Seguir link",
|
||||
@ -102,7 +100,31 @@
|
||||
"show_watch_on_youtube": "Mostrar Botão Assistir no YouTube",
|
||||
"minimize_chapters_default": "Minimizar Capítulos por padrão",
|
||||
"no_valid_playlists": "O arquivo não contém playlists válidas!",
|
||||
"with_playlist": "Compartilhar com playlist"
|
||||
"with_playlist": "Compartilhar com playlist",
|
||||
"bookmark_playlist": "Favorito",
|
||||
"playlist_bookmarked": "Favoritado",
|
||||
"skip_automatically": "Automaticamente",
|
||||
"skip_segment": "Ignorar Segmento",
|
||||
"min_segment_length": "Comprimento Mínimo do Segmento (em segundos)",
|
||||
"skip_button_only": "Mostrar botão pular",
|
||||
"show_less": "Mostrar menos",
|
||||
"autoplay_next_countdown": "Contagem regressiva padrão até o próximo vídeo (em segundos)",
|
||||
"dismiss": "Liberar",
|
||||
"cancel": "Cancelar",
|
||||
"edit_playlist": "Editar playlist",
|
||||
"playlist_description": "Descrição da playlist",
|
||||
"okay": "Ok",
|
||||
"playlist_name": "Nome da playlist",
|
||||
"auto_display_captions": "Exibição Automática de Legendas",
|
||||
"create_group": "Criar grupo",
|
||||
"group_name": "Nome do grupo",
|
||||
"show_search_suggestions": "Mostrar sugestões de pesquisa",
|
||||
"chapters_layout_mobile": "Layout dos Capítulos no Celular",
|
||||
"delete_automatically": "Deletar automaticamente após",
|
||||
"generate_qrcode": "Gerar código QR",
|
||||
"enable_dearrow": "Ativar DeArrow",
|
||||
"import_from_json_csv": "Importar de JSON/CSV",
|
||||
"download_frame": "Baixar quadro"
|
||||
},
|
||||
"titles": {
|
||||
"history": "Histórico",
|
||||
@ -117,10 +139,14 @@
|
||||
"player": "Player",
|
||||
"account": "Conta",
|
||||
"channels": "Canais",
|
||||
"livestreams": "Transmissões ao vivo"
|
||||
"livestreams": "Transmissões ao vivo",
|
||||
"bookmarks": "Favoritos",
|
||||
"channel_groups": "Grupos de Canais",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Assistir no {0}"
|
||||
"watch_on": "Assistir no {0}",
|
||||
"failed": "Falhou com código de erro {0}, veja os logs para mais informações"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Fixado por {author}",
|
||||
@ -139,7 +165,9 @@
|
||||
},
|
||||
"login": {
|
||||
"username": "Nome de usuário",
|
||||
"password": "Senha"
|
||||
"password": "Senha",
|
||||
"password_confirm": "Confirme senha",
|
||||
"passwords_incorrect": "As senhas não correspondem!"
|
||||
},
|
||||
"video": {
|
||||
"videos": "Vídeos",
|
||||
@ -149,7 +177,13 @@
|
||||
"watched": "Assistido",
|
||||
"ratings_disabled": "Avaliações Desativadas",
|
||||
"sponsor_segments": "Segmentos de Patrocinadores",
|
||||
"shorts": "Shorts"
|
||||
"shorts": "Shorts",
|
||||
"all": "Todos",
|
||||
"category": "Categoria",
|
||||
"chapters_horizontal": "Horizontal",
|
||||
"chapters_vertical": "Vertical",
|
||||
"license": "Licença",
|
||||
"visibility": "Visibilidade"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Você quis dizer: {0}?",
|
||||
@ -160,14 +194,21 @@
|
||||
"music_videos": "YT Music: Vídeos",
|
||||
"music_albums": "YT Music: Álbuns",
|
||||
"music_playlists": "YT Music: Playlists",
|
||||
"all": "YouTube: Tudo"
|
||||
"all": "YouTube: Tudo",
|
||||
"music_artists": "YT Music: Artistas"
|
||||
},
|
||||
"info": {
|
||||
"copied": "Copiado!",
|
||||
"cannot_copy": "Não foi possível copiar!",
|
||||
"preferences_note": "Nota: as preferências são salvas no armazenamento local do seu navegador. A exclusão dos dados do seu navegador irá redefini-los.",
|
||||
"page_not_found": "página não encontrada",
|
||||
"local_storage": "Esta ação requer localStorage, os cookies estão ativados?"
|
||||
"local_storage": "Esta ação requer localStorage, os cookies estão ativados?",
|
||||
"register_no_email_note": "Usar um e-mail como nome de usuário não é recomendado. Continuar mesmo assim?",
|
||||
"next_video_countdown": "Reproduzindo o próximo vídeo em {0}s",
|
||||
"hours": "{amount} hora(s)",
|
||||
"days": "{amount} dia(s)",
|
||||
"weeks": "{amount} semana(s)",
|
||||
"months": "{amount} mês/meses"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Inscrito em: {0}"
|
||||
|
@ -1,135 +1,158 @@
|
||||
{
|
||||
"titles": {
|
||||
"preferences": "Configurações",
|
||||
"preferences": "Preferências",
|
||||
"history": "Histórico",
|
||||
"feed": "Conteúdo",
|
||||
"subscriptions": "Subscrições",
|
||||
"trending": "Tendências",
|
||||
"login": "Iniciar Sessão",
|
||||
"login": "Iniciar sessão",
|
||||
"register": "Registar",
|
||||
"playlists": "Listas de Reprodução",
|
||||
"playlists": "Listas de reprodução",
|
||||
"account": "Conta",
|
||||
"instance": "Instância",
|
||||
"player": "Reprodutor",
|
||||
"livestreams": "Transmissões ao vivo",
|
||||
"channels": "Canais"
|
||||
"livestreams": "Emissões em direto",
|
||||
"channels": "Canais",
|
||||
"bookmarks": "Marcadores",
|
||||
"channel_groups": "Grupos de canais",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"actions": {
|
||||
"view_subscriptions": "Ver Subscrições",
|
||||
"view_subscriptions": "Ver subscrições",
|
||||
"sort_by": "Ordenar por:",
|
||||
"most_recent": "Mais Recente",
|
||||
"least_recent": "Menos Recente",
|
||||
"channel_name_asc": "Nome do Canal (A-Z)",
|
||||
"channel_name_desc": "Nome do Canal (Z-A)",
|
||||
"most_recent": "Mais recentes",
|
||||
"least_recent": "Mais antigos",
|
||||
"channel_name_asc": "Nome do canal (A-Z)",
|
||||
"channel_name_desc": "Nome do canal (Z-A)",
|
||||
"uses_api_from": "Utiliza a \"API\" de ",
|
||||
"enable_sponsorblock": "Ativar \"SponsorBlock\"",
|
||||
"skip_sponsors": "Saltar Patrocínios",
|
||||
"skip_intro": "Saltar Intermissão/Animação de Introdução",
|
||||
"skip_outro": "Saltar \"Endcards\"/Créditos",
|
||||
"skip_preview": "Saltar Pré-Visualização/Recapitulação",
|
||||
"skip_interaction": "Saltar Lembrete de Interação (Subscreve)",
|
||||
"skip_self_promo": "Saltar Promoção Não Paga/Auto-Promoção",
|
||||
"skip_non_music": "Saltar Música: Secção Não-Musical",
|
||||
"skip_highlight": "Saltar Destaque",
|
||||
"skip_filler_tangent": "Saltar Tangente \"Filler\"",
|
||||
"skip_sponsors": "Ignorar patrocínios",
|
||||
"skip_intro": "Ignorar intermissão/animação de introdução",
|
||||
"skip_outro": "Ignorar \"Endcards\"/Créditos",
|
||||
"skip_preview": "Ignorar pré-visualização/recapitulando",
|
||||
"skip_interaction": "Ignorar lembrete de interação (subscrição)",
|
||||
"skip_self_promo": "Ignorar promoção gratuita/auto-promoção",
|
||||
"skip_non_music": "Ignorar música: secção não musical",
|
||||
"skip_highlight": "Ignorar destaques",
|
||||
"skip_filler_tangent": "Ignorar segmentos de preenchimento",
|
||||
"theme": "Tema",
|
||||
"auto": "Automático",
|
||||
"dark": "Escuro",
|
||||
"light": "Claro",
|
||||
"buffering_goal": "Objetivo de \"Buffering\" (em segundos)",
|
||||
"country_selection": "Seleção de País",
|
||||
"default_homepage": "Página Inicial Padrão",
|
||||
"show_comments": "Mostrar Comentários",
|
||||
"minimize_description_default": "Minimizar Descrição por defeito",
|
||||
"store_watch_history": "Guardar Histórico de Visualizações",
|
||||
"language_selection": "Seleção de Idioma",
|
||||
"enabled_codecs": "\"Codecs\" Activados (Vários)",
|
||||
"instance_selection": "Seleção de Instância",
|
||||
"show_more": "Mostrar Mais",
|
||||
"buffering_goal": "Objetivo de 'buffer' (em segundos)",
|
||||
"country_selection": "País",
|
||||
"default_homepage": "Página inicial padrão",
|
||||
"show_comments": "Mostrar comentários",
|
||||
"minimize_description_default": "Minimizar descrição por omissão",
|
||||
"store_watch_history": "Guardar histórico de visualizações",
|
||||
"language_selection": "Idioma",
|
||||
"enabled_codecs": "Codificadores ativados (vários)",
|
||||
"instance_selection": "Instância",
|
||||
"show_more": "Mostrar mais",
|
||||
"import_from_json": "Importar de JSON/CSV",
|
||||
"loop_this_video": "Repetir este Vídeo",
|
||||
"auto_play_next_video": "Reproduzir Automaticamente o próximo Vídeo",
|
||||
"donations": "Doações de desenvolvimento",
|
||||
"minimize_description": "Minimizar Descrição",
|
||||
"show_description": "Mostrar Descrição",
|
||||
"minimize_recommendations": "Minimizar Recomendações",
|
||||
"show_recommendations": "Mostrar Recomendações",
|
||||
"view_ssl_score": "Ver Pontuação \"SSL\"",
|
||||
"search": "Procurar",
|
||||
"hide_replies": "Ocultar Respostas",
|
||||
"load_more_replies": "Carregar mais Respostas",
|
||||
"loop_this_video": "Repetir este vídeo",
|
||||
"auto_play_next_video": "Reproduzir vídeo seguinte automaticamente",
|
||||
"donations": "Doações para o desenvolvimento",
|
||||
"minimize_description": "Minimizar descrição",
|
||||
"show_description": "Mostrar descrição",
|
||||
"minimize_recommendations": "Minimizar recomendações",
|
||||
"show_recommendations": "Mostrar recomendações",
|
||||
"view_ssl_score": "Ver avaliação \"SSL\"",
|
||||
"search": "Pesquisa (Ctrl+K)",
|
||||
"hide_replies": "Ocultar respostas",
|
||||
"load_more_replies": "Carregar mais respostas",
|
||||
"unsubscribe": "Anular subscrição - {count}",
|
||||
"subscribe": "Subscrever - {count}",
|
||||
"back": "Voltar",
|
||||
"audio_only": "Apenas Áudio",
|
||||
"default_quality": "Qualidade Padrão",
|
||||
"instances_list": "Lista de Instâncias",
|
||||
"back": "Recuar",
|
||||
"audio_only": "Apenas áudio",
|
||||
"default_quality": "Qualidade padrão",
|
||||
"instances_list": "Lista de instâncias",
|
||||
"export_to_json": "Exportar para JSON",
|
||||
"autoplay_video": "Reproduzir Vídeo Automaticamente",
|
||||
"autoplay_video": "Reproduzir vídeos automaticamente",
|
||||
"yes": "Sim",
|
||||
"enable_lbry_proxy": "Activar \"Proxy\" para \"LBRY\"",
|
||||
"enable_lbry_proxy": "Ativar proxy para \"LBRY\"",
|
||||
"no": "Não",
|
||||
"filter": "Filtrar",
|
||||
"clear_history": "Limpar Histórico",
|
||||
"disable_lbry": "Desactivar \"LBRY\" para Transmissão",
|
||||
"loading": "A Carregar...",
|
||||
"please_select_playlist": "Selecionar uma lista de reprodução se faz favor",
|
||||
"select_playlist": "Selecionar uma Lista de Reprodução",
|
||||
"clear_history": "Limpar histórico",
|
||||
"disable_lbry": "Desativar \"LBRY\" para emissões",
|
||||
"loading": "A carregar...",
|
||||
"please_select_playlist": "Selecione uma lista de reprodução",
|
||||
"select_playlist": "Selecionar uma lista de reprodução",
|
||||
"add_to_playlist": "Adicionar à lista de reprodução",
|
||||
"delete_playlist": "Apagar Lista de Reprodução",
|
||||
"delete_playlist": "Apagar lista de reprodução",
|
||||
"download_as_txt": "Descarregar como .txt",
|
||||
"delete_playlist_confirm": "Apagar esta lista de reprodução?",
|
||||
"show_markers": "Mostrar Marcadores no Leitor",
|
||||
"show_markers": "Mostrar marcas no reprodutor",
|
||||
"remove_from_playlist": "Remover da lista de reprodução",
|
||||
"delete_playlist_video_confirm": "Remover o vídeo da lista de reprodução?",
|
||||
"create_playlist": "Criar Lista de Reprodução",
|
||||
"delete_account": "Apagar Conta",
|
||||
"logout": "Terminar sessão neste aparelho",
|
||||
"minimize_recommendations_default": "Minimizar Recomendações por defeito",
|
||||
"delete_playlist_video_confirm": "Remover vídeo da lista de reprodução?",
|
||||
"create_playlist": "Criar lista de reprodução",
|
||||
"delete_account": "Apagar conta",
|
||||
"logout": "Terminar sessão neste dispositivo",
|
||||
"minimize_recommendations_default": "Minimizar recomendações por omissão",
|
||||
"different_auth_instance": "Usar uma instância diferente para autenticação",
|
||||
"instance_auth_selection": "Selecção da Instância para Autenticação",
|
||||
"invalidate_session": "Terminar sessão em todos os aparelhos",
|
||||
"clone_playlist": "Clonar Lista de Reprodução",
|
||||
"instance_auth_selection": "Instância de autenticação",
|
||||
"invalidate_session": "Terminar sessão em todos os dispositivos",
|
||||
"clone_playlist": "Clonar lista de reprodução",
|
||||
"clone_playlist_success": "Clonada com sucesso!",
|
||||
"rename_playlist": "Renomear",
|
||||
"restore_preferences": "Restaurar configurações",
|
||||
"confirm_reset_preferences": "Tem a certeza que quer redefinir as suas configurações?",
|
||||
"new_playlist_name": "Novo nome da lista de reprodução",
|
||||
"restore_preferences": "Restaurar preferências",
|
||||
"confirm_reset_preferences": "Tem a certeza de que deseja repor as preferências?",
|
||||
"share": "Partilhar",
|
||||
"with_timecode": "Partilhar com código de tempo",
|
||||
"piped_link": "Ligação do Piped",
|
||||
"follow_link": "Seguir ligação",
|
||||
"copy_link": "Copiar ligação",
|
||||
"time_code": "Código de tempo (em segundos)",
|
||||
"reset_preferences": "Redefinir preferências",
|
||||
"backup_preferences": "Exportar configurações",
|
||||
"reset_preferences": "Repor preferências",
|
||||
"backup_preferences": "Exportar preferências",
|
||||
"back_to_home": "Voltar ao início",
|
||||
"minimize_comments_default": "Minimizar Comentários por defeito",
|
||||
"store_search_history": "Armazenar Histórico de Pesquisa",
|
||||
"minimize_chapters_default": "Minimizar Capítulos por padrão",
|
||||
"show_watch_on_youtube": "Mostrar Botão Assistir no YouTube",
|
||||
"minimize_comments_default": "Minimizar comentários por omissão",
|
||||
"store_search_history": "Histórico de pesquisa da loja",
|
||||
"minimize_chapters_default": "Minimizar capítulos por omissão",
|
||||
"show_watch_on_youtube": "Mostrar botão Ver no YouTube",
|
||||
"show_chapters": "Capítulos",
|
||||
"hide_watched": "Ocultar vídeos assistidos no feed",
|
||||
"hide_watched": "Ocultar do feed os vídeos visualizados",
|
||||
"documentation": "Documentação",
|
||||
"status_page": "Estado",
|
||||
"minimize_comments": "Minimizar Comentários",
|
||||
"minimize_comments": "Minimizar comentários",
|
||||
"reply_count": "{count} respostas",
|
||||
"source_code": "Código-fonte",
|
||||
"instance_donations": "Doações de instâncias",
|
||||
"no_valid_playlists": "O ficheiro não contém listas de reprodução válidas!"
|
||||
"no_valid_playlists": "O ficheiro não contém listas de reprodução válidas!",
|
||||
"bookmark_playlist": "Marcador",
|
||||
"playlist_bookmarked": "Marcado",
|
||||
"with_playlist": "Partilhar com lista de reprodução",
|
||||
"skip_button_only": "Mostrar botão Ignorar",
|
||||
"skip_automatically": "Automaticamente",
|
||||
"min_segment_length": "Tamanho mínimo do segmento (segundos)",
|
||||
"skip_segment": "Ignorar segmento",
|
||||
"show_less": "Mostrar menos",
|
||||
"autoplay_next_countdown": "Contagem decrescente até ao próximo vídeo (em segundos)",
|
||||
"dismiss": "Ignorar",
|
||||
"create_group": "Criar grupo",
|
||||
"group_name": "Nome do grupo",
|
||||
"auto_display_captions": "Mostrar legendas",
|
||||
"playlist_description": "Descrição da lista de reprodução",
|
||||
"edit_playlist": "Editar lista de reprodução",
|
||||
"playlist_name": "Nome da lista de reprodução",
|
||||
"cancel": "Cancelar",
|
||||
"okay": "Ok",
|
||||
"show_search_suggestions": "Mostrar sugestões de pesquisa",
|
||||
"chapters_layout_mobile": "Aplicações recentemente adicionadas",
|
||||
"enable_dearrow": "Ativar o DeArrow",
|
||||
"delete_automatically": "Eliminar automaticamente após"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Afixado por {author}",
|
||||
"disabled": "Os comentários estão desactivados pelo dono do canal.",
|
||||
"user_disabled": "Os comentários estão desactivados nas definições.",
|
||||
"disabled": "O dono do canal desativou os comentários.",
|
||||
"user_disabled": "Os comentários estão desativados nas definições.",
|
||||
"loading": "A carregar comentários..."
|
||||
},
|
||||
"preferences": {
|
||||
"instance_name": "Nome da Instância",
|
||||
"instance_locations": "Localizações da Instância",
|
||||
"has_cdn": "Tem \"CDN\"?",
|
||||
"registered_users": "Utilizadores Registados",
|
||||
"ssl_score": "Pontuação \"SSL\"",
|
||||
"instance_name": "Nome da instância",
|
||||
"instance_locations": "Localizações da instância",
|
||||
"has_cdn": "Tem CDN?",
|
||||
"registered_users": "Utilizadores registados",
|
||||
"ssl_score": "Avaliação SSL",
|
||||
"up_to_date": "Atualizada?",
|
||||
"version": "Versão"
|
||||
},
|
||||
@ -141,34 +164,47 @@
|
||||
"videos": "Vídeos",
|
||||
"views": "{views} visualizações",
|
||||
"watched": "Visto",
|
||||
"sponsor_segments": "Segmentos Patrocinados",
|
||||
"ratings_disabled": "Classificações Desactivadas",
|
||||
"sponsor_segments": "Segmentos patrocinados",
|
||||
"ratings_disabled": "Avaliações desativadas",
|
||||
"chapters": "Capítulos",
|
||||
"live": "{0} em Direto",
|
||||
"shorts": "\"Shorts\""
|
||||
"live": "{0} em direto",
|
||||
"shorts": "Curtos",
|
||||
"all": "Todos",
|
||||
"category": "Categoria",
|
||||
"chapters_horizontal": "Horizontal",
|
||||
"chapters_vertical": "Vertical",
|
||||
"license": "Licença",
|
||||
"visibility": "Visibilidade"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Será que querias dizer: {0}?",
|
||||
"did_you_mean": "Será que queria dizer: {0}?",
|
||||
"all": "YouTube: Tudo",
|
||||
"videos": "YouTube: Vídeos",
|
||||
"channels": "YouTube: Canais",
|
||||
"playlists": "YouTube: Listas de Reprodução",
|
||||
"playlists": "YouTube: Listas de reprodução",
|
||||
"music_songs": "YT Music: Músicas",
|
||||
"music_videos": "YT Music: Vídeos",
|
||||
"music_albums": "YT Music: Álbuns",
|
||||
"music_playlists": "YT Music: Listas de Reprodução"
|
||||
"music_playlists": "YT Music: Listas de reprodução",
|
||||
"music_artists": "YT Music: Artistas"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Ver em {0}"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Subscrito a: {0}"
|
||||
"subscribed_channels_count": "Subscreveu: {0}"
|
||||
},
|
||||
"info": {
|
||||
"preferences_note": "Nota: as configurações são guardadas no armazenamento local to seu navegador. Eliminar os dados de navegação irá redefini-las.",
|
||||
"preferences_note": "Nota: as preferências são guardadas no armazenamento local do seu navegador. Se limpar os dados de navegação, também limpa as preferências.",
|
||||
"page_not_found": "Página não encontrada",
|
||||
"copied": "Copiada!",
|
||||
"cannot_copy": "Não foi possível copiar!",
|
||||
"local_storage": "Esta ação requer localStorage, os cookies estão ativados?"
|
||||
"local_storage": "Esta ação requer localStorage, os cookies estão ativados?",
|
||||
"register_no_email_note": "Não recomendamos utilizar um endereço de e-mail como nome de utilizador. Continuar?",
|
||||
"next_video_countdown": "A reproduzir o vídeo seguinte em {0}s",
|
||||
"hours": "{quantidade} hora(s)",
|
||||
"days": "{quantidade} dia(s)",
|
||||
"weeks": "{quantidade} semana(s)",
|
||||
"months": "{quantidade} mês(es)"
|
||||
}
|
||||
}
|
||||
|
@ -1,152 +1,182 @@
|
||||
{
|
||||
"actions": {
|
||||
"back_to_home": "Înapoi acasă",
|
||||
"store_search_history": "Salveaza Istoric de Cautări",
|
||||
"with_timecode": "Distribuie cu cod de timp",
|
||||
"store_search_history": "Rețineți istoricul de căutări",
|
||||
"with_timecode": "Distribuiți cu timpul de cod",
|
||||
"piped_link": "Link Piped",
|
||||
"time_code": "Cod de timp (secunde)",
|
||||
"show_chapters": "Capitole",
|
||||
"search": "Caută",
|
||||
"logout": "Scoate contul de pe acest dispozitiv",
|
||||
"add_to_playlist": "Adaugă în Playlist",
|
||||
"remove_from_playlist": "Șterge din Playlist",
|
||||
"create_playlist": "Creează Playlist",
|
||||
"delete_playlist": "Șterge Playlist",
|
||||
"delete_playlist_confirm": "Ștergi acest playlist?",
|
||||
"please_select_playlist": "Te rog să alegi un playlist",
|
||||
"minimize_recommendations_default": "Ascunde Recomandări ca default",
|
||||
"subscribe": "Abonează-te - {count}",
|
||||
"least_recent": "Mai puțin recente",
|
||||
"channel_name_asc": "Nume Canal (A-Z)",
|
||||
"channel_name_desc": "Nume Canal (Z-A)",
|
||||
"search": "Căutare (Ctrl+K)",
|
||||
"logout": "Deconectați-vă de pe acest dispozitiv",
|
||||
"add_to_playlist": "Adăugare în playlist",
|
||||
"remove_from_playlist": "Ștergere din playlist",
|
||||
"create_playlist": "Creați playlist",
|
||||
"delete_playlist": "Ștergeți playlist",
|
||||
"delete_playlist_confirm": "Ștergeți acest playlist?",
|
||||
"please_select_playlist": "Vă rugăm să alegeți un playlist",
|
||||
"minimize_recommendations_default": "Minimizați recomandările în mod implicit",
|
||||
"subscribe": "Abonare - {count}",
|
||||
"least_recent": "Cele mai vechi",
|
||||
"channel_name_asc": "Numele canalului (A-Z)",
|
||||
"channel_name_desc": "Nume canalului (Z-A)",
|
||||
"back": "Înapoi",
|
||||
"uses_api_from": "Folosește API de la ",
|
||||
"enable_sponsorblock": "Activează Sponsorblock",
|
||||
"skip_intro": "Sari animația de Intermisie / Intro",
|
||||
"skip_preview": "Sari Preview / Recapitulare",
|
||||
"skip_self_promo": "Sari Promoția Neplătita / Proprie",
|
||||
"skip_non_music": "Sari Muzica: Secțiunea de Non-Muzică",
|
||||
"skip_highlight": "Sari Highlight",
|
||||
"show_markers": "Arată Marcaje in Player",
|
||||
"uses_api_from": "Se folosește API-ul de la ",
|
||||
"enable_sponsorblock": "Activați Sponsorblock",
|
||||
"skip_intro": "Omitere pauze/animații de intro",
|
||||
"skip_preview": "Omitere previzualizare/recapitulare",
|
||||
"skip_self_promo": "Omitere promoție neplătită/autopromovare",
|
||||
"skip_non_music": "Omitere muzică: Secțiune non-muzicală",
|
||||
"skip_highlight": "Omitere evidențiere",
|
||||
"show_markers": "Se afișează marcatori în player",
|
||||
"dark": "Întunecat",
|
||||
"auto": "Auto",
|
||||
"audio_only": "Doar Audio",
|
||||
"default_quality": "Calitate Default",
|
||||
"country_selection": "Selecție Țară",
|
||||
"default_homepage": "Pagina de Acasă",
|
||||
"minimize_comments_default": "Ascunde Comentariile",
|
||||
"minimize_description_default": "Ascunde Descrierea",
|
||||
"language_selection": "Selecție Limbă",
|
||||
"audio_only": "Doar audio",
|
||||
"default_quality": "Calitate implicită",
|
||||
"country_selection": "Țară",
|
||||
"default_homepage": "Pagina principală implicită",
|
||||
"minimize_comments_default": "Minimizați comentariile în mod implicit",
|
||||
"minimize_description_default": "Minimizați descrierea în mod implicit",
|
||||
"language_selection": "Limbă",
|
||||
"instances_list": "Listă de Instanțe",
|
||||
"enabled_codecs": "Activează Codecuri (Multiple)",
|
||||
"loop_this_video": "Repornește Video-ul",
|
||||
"donations": "Donații",
|
||||
"show_recommendations": "Arată Recomandări",
|
||||
"disable_lbry": "Oprește LBRY pentru Streaming",
|
||||
"enable_lbry_proxy": "Activează Proxy pentru LBRY",
|
||||
"view_ssl_score": "Vezi Scor SSL",
|
||||
"enabled_codecs": "Codecuri activate (multiple)",
|
||||
"loop_this_video": "Repetare video",
|
||||
"donations": "Donații pentru dezvoltare",
|
||||
"show_recommendations": "Afișați recomandările",
|
||||
"disable_lbry": "Dezactivați LBRY pentru streaming",
|
||||
"enable_lbry_proxy": "Activați proxy pentru LBRY",
|
||||
"view_ssl_score": "Vedeți scorul SSL",
|
||||
"filter": "Filtru",
|
||||
"loading": "Se încarcă...",
|
||||
"clear_history": "Șterge Istoric",
|
||||
"hide_replies": "Ascunde răspunsuri",
|
||||
"load_more_replies": "Mai multe Răspunsuri",
|
||||
"delete_playlist_video_confirm": "Ștergi video-ul din playlist?",
|
||||
"select_playlist": "Alege un Playlist",
|
||||
"delete_account": "Șterge Contul",
|
||||
"show_watch_on_youtube": "Arata buton de Vezi pe YouTube",
|
||||
"invalidate_session": "Deconectează-te peste tot",
|
||||
"instance_auth_selection": "Selecție Instanță de Autentificare",
|
||||
"clone_playlist_success": "Clonat cu succes!",
|
||||
"reset_preferences": "Resetează preferințele",
|
||||
"confirm_reset_preferences": "Sigur vrei să îți resetezi preferințele?",
|
||||
"rename_playlist": "Redenumește playlist",
|
||||
"new_playlist_name": "Nume playlist nou",
|
||||
"share": "Distribuie",
|
||||
"follow_link": "Deschide link",
|
||||
"copy_link": "Copiază link",
|
||||
"hide_watched": "Ascunde video-urile vizionate",
|
||||
"clear_history": "Ștergeți istoricul",
|
||||
"hide_replies": "Ascundeți răspunsurile",
|
||||
"load_more_replies": "Mai multe răspunsuri",
|
||||
"delete_playlist_video_confirm": "Ștergeți videoclipul din playlist?",
|
||||
"select_playlist": "Selectați un playlist",
|
||||
"delete_account": "Ștergeți-vă contul",
|
||||
"show_watch_on_youtube": "Afișați butonul „Vizionați pe YouTube”",
|
||||
"invalidate_session": "Deconectați toate dispozitivele",
|
||||
"instance_auth_selection": "Instanța de autentificare",
|
||||
"clone_playlist_success": "Clonată cu succes!",
|
||||
"reset_preferences": "Resetați preferințele",
|
||||
"confirm_reset_preferences": "Sunteți sigur că doriți să vă resetați preferințele?",
|
||||
"share": "Distribuiți",
|
||||
"follow_link": "Urmați link-ul",
|
||||
"copy_link": "Copiați link-ul",
|
||||
"hide_watched": "Ascundeți videoclipurile vizionate din flux",
|
||||
"documentation": "Documentație",
|
||||
"status_page": "Status",
|
||||
"source_code": "Cod sursă",
|
||||
"instance_donations": "Donații instanță",
|
||||
"reply_count": "{count} răspunsuri",
|
||||
"minimize_chapters_default": "Ascunde Capitole ca default",
|
||||
"skip_sponsors": "Sari Sponsori",
|
||||
"different_auth_instance": "Folosește altă instanță pentru autentificare",
|
||||
"clone_playlist": "Clonează Playlist",
|
||||
"backup_preferences": "Backup preferințe",
|
||||
"unsubscribe": "Dezabonează-te - {count}",
|
||||
"view_subscriptions": "Vezi Subscripții",
|
||||
"sort_by": "Sortează după:",
|
||||
"download_as_txt": "Descarcă ca .txt",
|
||||
"most_recent": "Cele mai Recente",
|
||||
"skip_outro": "Sari Endcards / Credite",
|
||||
"skip_interaction": "Sari Reminder de interacțiune (Subscribe)",
|
||||
"minimize_chapters_default": "Minimizați capitolele în mod implicit",
|
||||
"skip_sponsors": "Omitere sponsori",
|
||||
"different_auth_instance": "Folosiți o instanță diferită pentru autentificare",
|
||||
"clone_playlist": "Clonați lista de redare",
|
||||
"backup_preferences": "Faceți backup la preferințe",
|
||||
"unsubscribe": "Dezabonare - {count}",
|
||||
"view_subscriptions": "Vedeți abonamentele",
|
||||
"sort_by": "Sortare după:",
|
||||
"download_as_txt": "Descărcați ca .txt",
|
||||
"most_recent": "Cele mai recente",
|
||||
"skip_outro": "Omitere carduri de sfârșit/mulțumiri",
|
||||
"skip_interaction": "Omitere reamintiri de interacțiune (abonare)",
|
||||
"light": "Luminat",
|
||||
"restore_preferences": "Restore preferințe",
|
||||
"skip_filler_tangent": "Sari Tangenta Filler",
|
||||
"restore_preferences": "Restaurați preferințele",
|
||||
"skip_filler_tangent": "Omitere tangentă de umplere",
|
||||
"theme": "Temă",
|
||||
"autoplay_video": "Autopornește Video",
|
||||
"buffering_goal": "Buffering Goal (secunde)",
|
||||
"instance_selection": "Selecție Instanță",
|
||||
"store_watch_history": "Salvează Istoricul de Vizionare",
|
||||
"minimize_comments": "Ascunde Comentarii",
|
||||
"minimize_description": "Ascunde Descriere",
|
||||
"show_more": "Mai Mult",
|
||||
"autoplay_video": "Redare automată video",
|
||||
"buffering_goal": "Obiectiv de tamponare (în secunde)",
|
||||
"instance_selection": "Instanță",
|
||||
"store_watch_history": "Rețineți istoricul de vizionări",
|
||||
"minimize_comments": "Minimizați comentariile",
|
||||
"minimize_description": "Minimizați descrierea",
|
||||
"show_more": "Mai mult",
|
||||
"no": "Nu",
|
||||
"export_to_json": "Exportă ca JSON",
|
||||
"import_from_json": "Importă din JSON/CSV",
|
||||
"auto_play_next_video": "Autopornește următorul Video",
|
||||
"minimize_recommendations": "Ascunde Recomandări",
|
||||
"export_to_json": "Exportați ca JSON",
|
||||
"import_from_json": "Importați din JSON/CSV",
|
||||
"auto_play_next_video": "Redați automat următorul video",
|
||||
"minimize_recommendations": "Minimizați recomandările",
|
||||
"yes": "Da",
|
||||
"show_comments": "Arată Comentarii",
|
||||
"show_description": "Arată Descriere"
|
||||
"show_comments": "Afișați comentariile",
|
||||
"show_description": "Afișați descrierea",
|
||||
"bookmark_playlist": "Marcați",
|
||||
"no_valid_playlists": "Fișierul nu conține playlist-uri valide!",
|
||||
"skip_automatically": "Automat",
|
||||
"min_segment_length": "Lungimea minimă a segmentului (în secunde)",
|
||||
"skip_segment": "Omitere segment",
|
||||
"skip_button_only": "Afișați butonul de omitere",
|
||||
"with_playlist": "Distribuiți cu playlist",
|
||||
"playlist_bookmarked": "Marcat",
|
||||
"show_less": "Mai puțin",
|
||||
"autoplay_next_countdown": "Numărătoarea inversă implicită până la următorul videoclip (în secunde)",
|
||||
"dismiss": "Concediază",
|
||||
"group_name": "Numele grupului",
|
||||
"create_group": "Creați un grup",
|
||||
"auto_display_captions": "Afișare automată subtitrări",
|
||||
"playlist_name": "Numele playlist-ului",
|
||||
"okay": "OK",
|
||||
"playlist_description": "Descrierea playlist-ului",
|
||||
"edit_playlist": "Editează playlist-ul",
|
||||
"cancel": "Anulare",
|
||||
"chapters_layout_mobile": "Mod afișare capitole pe mobil",
|
||||
"show_search_suggestions": "Afișare sugestii căutare",
|
||||
"enable_dearrow": "Activați DeArrow",
|
||||
"delete_automatically": "Șterge automat după"
|
||||
},
|
||||
"preferences": {
|
||||
"ssl_score": "Scor SSL",
|
||||
"version": "Versiune",
|
||||
"up_to_date": "Actualizat?",
|
||||
"instance_name": "Nume Instanță",
|
||||
"instance_locations": "Locațiile Instanței",
|
||||
"instance_name": "Nume instanță",
|
||||
"instance_locations": "Locațiile instanței",
|
||||
"has_cdn": "Are CDN?",
|
||||
"registered_users": "Useri Înregistrați"
|
||||
"registered_users": "Utilizatori înregistrați"
|
||||
},
|
||||
"comment": {
|
||||
"user_disabled": "Comentariile sunt dezactivate în setări.",
|
||||
"pinned_by": "Pomovat de {author}",
|
||||
"disabled": "Comentariile sunt dezactivate de creator.",
|
||||
"loading": "Se incarcă comentariile..."
|
||||
"pinned_by": "Fixat de {author}",
|
||||
"disabled": "Comentariile sunt dezactivate de către autor.",
|
||||
"loading": "Se încarcă comentariile..."
|
||||
},
|
||||
"video": {
|
||||
"views": "{views} vizionări",
|
||||
"chapters": "Capitole",
|
||||
"shorts": "Shorts",
|
||||
"watched": "Văzut",
|
||||
"sponsor_segments": "Segmente Sponsori",
|
||||
"ratings_disabled": "Like-uri dezactivate",
|
||||
"live": "{0} Live",
|
||||
"videos": "Video-uri"
|
||||
"watched": "Vizionat",
|
||||
"sponsor_segments": "Segmente sponsori",
|
||||
"ratings_disabled": "Evaluări dezactivate",
|
||||
"live": "{0} în direct",
|
||||
"videos": "Videoclipuri",
|
||||
"category": "Categorie",
|
||||
"all": "Tot",
|
||||
"chapters_horizontal": "Orizontal",
|
||||
"chapters_vertical": "Vertical"
|
||||
},
|
||||
"login": {
|
||||
"username": "Nume User",
|
||||
"username": "Nume de utilizator",
|
||||
"password": "Parolă"
|
||||
},
|
||||
"search": {
|
||||
"videos": "YouTube: Video-uri",
|
||||
"music_playlists": "YT Music: Playlisturi",
|
||||
"did_you_mean": "Voiai să scrii: {0}?",
|
||||
"videos": "YouTube: Videoclipuri",
|
||||
"music_playlists": "YT Music: Liste de redare",
|
||||
"did_you_mean": "Vă refereați la: {0}?",
|
||||
"all": "YouTube: Toate",
|
||||
"channels": "YouTube: Canale",
|
||||
"playlists": "YouTube: Playlisturi",
|
||||
"music_songs": "YT Music: Cântece",
|
||||
"music_videos": "YT Music: Video-uri",
|
||||
"music_albums": "YT Music: Albume"
|
||||
"playlists": "YouTube: Liste de redare",
|
||||
"music_songs": "YT Music: Muzică",
|
||||
"music_videos": "YT Music: Videoclipuri",
|
||||
"music_albums": "YT Music: Albume",
|
||||
"music_artists": "YT Music: Artiști"
|
||||
},
|
||||
"info": {
|
||||
"cannot_copy": "Nu se poate copia!",
|
||||
"preferences_note": "Sfat: preferințele sunt salvate in memoria locala a browserului tău. Ștergând datele browserului le ștergi si pe ele.",
|
||||
"page_not_found": "Pagină negăsită",
|
||||
"copied": "S-a copiat!"
|
||||
"cannot_copy": "Nu s-a putut copia!",
|
||||
"preferences_note": "Notă: preferințele sunt salvate în memoria locală a browserului dvs. Ștergerea datelor din browserul dvs. le va reseta.",
|
||||
"page_not_found": "Pagina nu a fost găsită",
|
||||
"copied": "Copiat!",
|
||||
"register_no_email_note": "Utilizarea unui e-mail ca nume de utilizator nu este recomandată. Continuați oricum?",
|
||||
"local_storage": "Această acțiune necesită localStorage, sunt activate cookie-urile?",
|
||||
"next_video_countdown": "Redarea următorului videoclip în {0}s",
|
||||
"days": "{amount} zi(le)"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Abonat la: {0}"
|
||||
@ -154,19 +184,22 @@
|
||||
"titles": {
|
||||
"register": "Înregistrare",
|
||||
"history": "Istoric",
|
||||
"subscriptions": "Abonări",
|
||||
"playlists": "Playlisturi",
|
||||
"subscriptions": "Abonamente",
|
||||
"playlists": "Liste de redare",
|
||||
"account": "Cont",
|
||||
"instance": "Instanță",
|
||||
"login": "Logare",
|
||||
"feed": "Abonări",
|
||||
"trending": "Trending",
|
||||
"livestreams": "Live-uri",
|
||||
"login": "Autentificare",
|
||||
"feed": "Flux",
|
||||
"trending": "Tendințe",
|
||||
"livestreams": "Fluxuri live",
|
||||
"channels": "Canale",
|
||||
"preferences": "Preferințe",
|
||||
"player": "Player"
|
||||
"player": "Player-ul",
|
||||
"bookmarks": "Marcaje",
|
||||
"channel_groups": "Grupuri de canale",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Vezi pe {0}"
|
||||
"watch_on": "Vizionați pe {0}"
|
||||
}
|
||||
}
|
||||
|
@ -5,14 +5,17 @@
|
||||
"register": "Регистрация",
|
||||
"feed": "Подписки",
|
||||
"preferences": "Настройки",
|
||||
"history": "История просмотров",
|
||||
"subscriptions": "Ваши подписки",
|
||||
"history": "История",
|
||||
"subscriptions": "Подписки",
|
||||
"playlists": "Плейлисты",
|
||||
"account": "Аккаунт",
|
||||
"player": "Плеер",
|
||||
"instance": "Сервер",
|
||||
"livestreams": "Прямые трансляции",
|
||||
"channels": "Каналы"
|
||||
"channels": "Каналы",
|
||||
"bookmarks": "Закладки",
|
||||
"channel_groups": "Группы каналов",
|
||||
"dearrow": "DeArrow"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Смотреть на {0}"
|
||||
@ -27,7 +30,7 @@
|
||||
"channel_name_asc": "Имя канала (А-Я)",
|
||||
"channel_name_desc": "Имя канала (Я-А)",
|
||||
"back": "Назад",
|
||||
"uses_api_from": "Использовать API, предоставляемое ",
|
||||
"uses_api_from": "Использовать API ",
|
||||
"enable_sponsorblock": "Включить Sponsorblock",
|
||||
"skip_sponsors": "Пропускать спонсорскую рекламу",
|
||||
"skip_intro": "Пропускать заставку/интро",
|
||||
@ -53,11 +56,11 @@
|
||||
"instances_list": "Список зеркал сервиса Piped",
|
||||
"enabled_codecs": "Включённые кодеки (Можно выбрать несколько)",
|
||||
"instance_selection": "Выбор зеркала сервиса Piped",
|
||||
"show_more": "Показать больше",
|
||||
"show_more": "Показать еще",
|
||||
"yes": "Да",
|
||||
"no": "Нет",
|
||||
"export_to_json": "Экспорт в JSON",
|
||||
"import_from_json": "Импорт из JSON/CSV",
|
||||
"import_from_json": "Импорт из JSON",
|
||||
"loop_this_video": "Повтор текущего видео",
|
||||
"auto_play_next_video": "Сразу проигрывать следующее рекомендованное видео",
|
||||
"donations": "Пожертвования на разработку",
|
||||
@ -66,9 +69,9 @@
|
||||
"minimize_recommendations": "Свернуть рекомендации",
|
||||
"show_recommendations": "Показать рекомендации",
|
||||
"disable_lbry": "Отключить LBRY для стриминга",
|
||||
"enable_lbry_proxy": "Проксировать видео с LBRY",
|
||||
"enable_lbry_proxy": "Проксировать видео для LBRY",
|
||||
"view_ssl_score": "Посмотреть настройки SSL",
|
||||
"search": "Поиск",
|
||||
"search": "Поиск (Ctrl+K)",
|
||||
"filter": "Фильтр",
|
||||
"loading": "Загрузка...",
|
||||
"clear_history": "Очистить историю",
|
||||
@ -84,52 +87,74 @@
|
||||
"select_playlist": "Выбрать плейлист",
|
||||
"delete_playlist_confirm": "Удалить этот плейлист?",
|
||||
"delete_playlist_video_confirm": "Удалить видео из плейлиста?",
|
||||
"show_markers": "Показать Mаркеры Hа Проигрывателе",
|
||||
"show_markers": "Показать маркеры на проигрывателе",
|
||||
"delete_account": "Удалить аккаунт",
|
||||
"logout": "Выйти из этого устройства",
|
||||
"download_as_txt": "Скачать как .txt",
|
||||
"minimize_recommendations_default": "Скрыть Рекомендации по умолчанию",
|
||||
"invalidate_session": "Выйти из всех устройств",
|
||||
"different_auth_instance": "Использовать другие средства аутентификации",
|
||||
"instance_auth_selection": "Выбор средств аутентификации",
|
||||
"different_auth_instance": "Использовать другое зеркало для аутентификации",
|
||||
"instance_auth_selection": "Выбор зеркала аутентификации",
|
||||
"clone_playlist": "Клонировать плейлист",
|
||||
"clone_playlist_success": "Клонирование прошло успешно!",
|
||||
"show_chapters": "Части",
|
||||
"rename_playlist": "Переименовать плейлист",
|
||||
"new_playlist_name": "Новое название плейлиста",
|
||||
"clone_playlist_success": "Успешно клонировано!",
|
||||
"show_chapters": "Главы",
|
||||
"share": "Поделиться",
|
||||
"with_timecode": "Поделиться с отметкой времени",
|
||||
"with_timecode": "Поделиться с таймкодом",
|
||||
"piped_link": "Ссылка Piped",
|
||||
"follow_link": "Ссылка подписки",
|
||||
"follow_link": "Перейти по ссылке",
|
||||
"copy_link": "Скопировать ссылку",
|
||||
"time_code": "Тайм-код (в секундах)",
|
||||
"time_code": "Таймкод (в секундах)",
|
||||
"reset_preferences": "Сбросить настройки",
|
||||
"confirm_reset_preferences": "Вы уверены, что хотите сбросить настройки?",
|
||||
"backup_preferences": "Бэкап настроек",
|
||||
"restore_preferences": "Восстановить настройки",
|
||||
"back_to_home": "Вернутся на главную",
|
||||
"back_to_home": "Назад на главную",
|
||||
"store_search_history": "Хранить историю поиска",
|
||||
"hide_watched": "Скрыть просмотренные видео в ленте",
|
||||
"status_page": "Статус",
|
||||
"source_code": "Исходный код",
|
||||
"documentation": "Пожертвования сервера",
|
||||
"instance_donations": "Пожертвования сервера",
|
||||
"documentation": "Документация",
|
||||
"instance_donations": "Пожертвования зеркала",
|
||||
"reply_count": "{count} ответов",
|
||||
"minimize_comments_default": "Сворачивать комментарии по умолчанию",
|
||||
"minimize_comments": "Свернуть комментарии",
|
||||
"show_watch_on_youtube": "Показать кнопку Смотреть на YouTube",
|
||||
"minimize_chapters_default": "Скрывать главы по умолчанию",
|
||||
"no_valid_playlists": "Файл не содержит действительных списков воспроизведения!"
|
||||
"no_valid_playlists": "Файл не содержит действующих плейлистов!",
|
||||
"with_playlist": "Поделиться с плейлистом",
|
||||
"bookmark_playlist": "Закладка",
|
||||
"playlist_bookmarked": "В закладках",
|
||||
"skip_automatically": "Автоматически",
|
||||
"min_segment_length": "Минимальная длина сегмента (в секундах)",
|
||||
"skip_button_only": "Показать кнопку \"Пропустить\"",
|
||||
"skip_segment": "Пропустить сегмент",
|
||||
"show_less": "Показать меньше",
|
||||
"autoplay_next_countdown": "Отсчет по умолчанию до следующего видео (в секундах)",
|
||||
"dismiss": "Отклонить",
|
||||
"group_name": "Имя группы",
|
||||
"create_group": "Создать группу",
|
||||
"cancel": "Отмена",
|
||||
"edit_playlist": "Редактировать плейлист",
|
||||
"playlist_description": "Описание плейлиста",
|
||||
"okay": "Хорошо",
|
||||
"auto_display_captions": "Авто-отображение субтитров",
|
||||
"playlist_name": "Название плейлиста",
|
||||
"show_search_suggestions": "Показать поисковые предложения",
|
||||
"chapters_layout_mobile": "Расположение глав в мобильном виде",
|
||||
"delete_automatically": "Автоматическое удаление после",
|
||||
"enable_dearrow": "Включить DeArrow",
|
||||
"generate_qrcode": "Сгенерировать QR Код",
|
||||
"import_from_json_csv": "Импорт из JSON/CSV"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Прикреплено пользователем {author}",
|
||||
"pinned_by": "Закреплено пользователем {author}",
|
||||
"loading": "Загрузка комментариев...",
|
||||
"user_disabled": "Комментарии отключены в настройках.",
|
||||
"disabled": "Коментарии отключены автором."
|
||||
"disabled": "Комментарии отключены автором."
|
||||
},
|
||||
"preferences": {
|
||||
"instance_name": "Название",
|
||||
"instance_locations": "Местоположение",
|
||||
"instance_name": "Имя зеркала",
|
||||
"instance_locations": "Местоположения зеркала",
|
||||
"has_cdn": "Имеется CDN?",
|
||||
"ssl_score": "Оценка настроек SSL",
|
||||
"registered_users": "Зарегистрировано пользователей",
|
||||
@ -137,8 +162,10 @@
|
||||
"up_to_date": "Версия актуальна?"
|
||||
},
|
||||
"login": {
|
||||
"username": "Аккаунт на Piped",
|
||||
"password": "Пароль"
|
||||
"username": "Имя пользователя",
|
||||
"password": "Пароль",
|
||||
"password_confirm": "Повторите пароль",
|
||||
"passwords_incorrect": "Пароль не совпадает!"
|
||||
},
|
||||
"video": {
|
||||
"videos": "Видео",
|
||||
@ -148,7 +175,13 @@
|
||||
"ratings_disabled": "Оценки отключены",
|
||||
"live": "{0} В эфире",
|
||||
"chapters": "Содержание",
|
||||
"shorts": "Shorts"
|
||||
"shorts": "Shorts",
|
||||
"all": "Все",
|
||||
"category": "Категория",
|
||||
"chapters_horizontal": "Горизонтально",
|
||||
"chapters_vertical": "Вертикально",
|
||||
"visibility": "Видимость",
|
||||
"license": "Лицензия"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "Может быть вы имели в виду: {0}?",
|
||||
@ -159,16 +192,23 @@
|
||||
"music_songs": "YT Music: Композиции",
|
||||
"music_videos": "YT Music: Видео",
|
||||
"music_albums": "YT Music: Альбомы",
|
||||
"music_playlists": "YT Music: Плейлисты"
|
||||
"music_playlists": "YT Music: Плейлисты",
|
||||
"music_artists": "YT Music: Исполнители"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Подписан на: {0}"
|
||||
},
|
||||
"info": {
|
||||
"preferences_note": "Примечание: настройки сохранены в локальном хранилище браузера. При удалении данных браузера они будут удалены.",
|
||||
"preferences_note": "Примечание: настройки сохранены в локальном хранилище браузера. Удаление данных вашего браузера сбросит их.",
|
||||
"copied": "Скопировано!",
|
||||
"cannot_copy": "Не получилось скопировать!",
|
||||
"cannot_copy": "Не удалось скопировать!",
|
||||
"page_not_found": "Страница не найдена",
|
||||
"local_storage": "Это действие требует локального хранилища (localStorage), разрешены ли файлы cookie?"
|
||||
"local_storage": "Это действие требует разрешения localStorage, включены ли cookie-файлы?",
|
||||
"register_no_email_note": "Использование электронной почты в качестве имени пользователя не рекомендуется. Продолжить?",
|
||||
"next_video_countdown": "Следующие видео через {0} с",
|
||||
"days": "{amount} дней",
|
||||
"hours": "{amount} час(ов)",
|
||||
"weeks": "{amount} недель",
|
||||
"months": "{amount} месяцев"
|
||||
}
|
||||
}
|
||||
|
207
src/locales/si.json
Normal file
207
src/locales/si.json
Normal file
@ -0,0 +1,207 @@
|
||||
{
|
||||
"titles": {
|
||||
"trending": "නැගී එන",
|
||||
"login": "පිවිසෙන්න",
|
||||
"register": "ලියාපදිංචිය",
|
||||
"preferences": "අභිප්රේත",
|
||||
"history": "ඉතිහාසය",
|
||||
"subscriptions": "දායකත්ව",
|
||||
"account": "ගිණුම",
|
||||
"player": "වාදකය",
|
||||
"livestreams": "සජීව ප්රචාර",
|
||||
"channels": "නාලිකා",
|
||||
"playlists": "වාදන ලැයිස්තු",
|
||||
"instance": "සේවාදායකය",
|
||||
"bookmarks": "පොත්යොමු",
|
||||
"feed": "සංග්රහය",
|
||||
"channel_groups": "නාලිකා සමූහ"
|
||||
},
|
||||
"actions": {
|
||||
"subscribe": "දායකවන්න - {count}",
|
||||
"unsubscribe": "දායක නොවන්න - {count}",
|
||||
"most_recent": "වඩාත් මෑත",
|
||||
"least_recent": "ආසන්න මෑත",
|
||||
"channel_name_asc": "නාලිකාවේ නම (අ-ෆ)",
|
||||
"channel_name_desc": "නාලිකාවේ නම (ෆ-අ)",
|
||||
"back": "ආපසු",
|
||||
"skip_sponsors": "අනුග්රහකයින් මඟහරින්න",
|
||||
"skip_outro": "අවසන් කාඩ්පත/දායක ලැයිස්තුව මඟ හරින්න",
|
||||
"skip_preview": "පෙරදසුන/සාරාංශය මඟ හරින්න",
|
||||
"skip_self_promo": "නොගෙවූ/ස්වයං ප්රවර්ධන මඟ හරින්න",
|
||||
"skip_filler_tangent": "අදාළ නොවන කොටස් මඟහරින්න",
|
||||
"theme": "තේමාව",
|
||||
"dark": "අඳුරු",
|
||||
"light": "දීප්ත",
|
||||
"autoplay_video": "දෘශ්යක ඉබේ වාදනය",
|
||||
"auto": "ස්වයං",
|
||||
"default_quality": "පෙරනිමි ගුණත්වය",
|
||||
"default_homepage": "පෙරනිමි මුල් පිටුව",
|
||||
"show_markers": "වාදකයේ මාකර් පෙන්වන්න",
|
||||
"buffering_goal": "අන්තරාචය ඉලක්කය (තත්. වලින්)",
|
||||
"enable_sponsorblock": "Sponsorblock සබල කරන්න",
|
||||
"sort_by": "පෙළගසන්න:",
|
||||
"skip_highlight": "ඉස්මතු කිරීම් මඟ හරින්න",
|
||||
"language_selection": "භාෂාව",
|
||||
"show_more": "තව පෙන්වන්න",
|
||||
"yes": "ඔව්",
|
||||
"no": "නැහැ",
|
||||
"export_to_json": "JSON ලෙස නිර්යාත කරන්න",
|
||||
"import_from_json": "JSON/CSV වෙතින් ආයාත කරන්න",
|
||||
"loop_this_video": "මෙම දෘශ්යකය පුඩුලන්න",
|
||||
"auto_play_next_video": "ඊළඟ දෘශ්යකය ඉබේ වාදනය කරන්න",
|
||||
"donations": "සංවර්ධන පරිත්යාග",
|
||||
"minimize_comments": "අදහස් හකුළන්න",
|
||||
"show_comments": "අදහස් පෙන්වන්න",
|
||||
"minimize_description": "විස්තරය හකුළන්න",
|
||||
"show_description": "සවිස්තරය පෙන්වන්න",
|
||||
"minimize_recommendations": "නිර්දේශ හකුළන්න",
|
||||
"show_recommendations": "නිර්දේශ පෙන්වන්න",
|
||||
"store_watch_history": "නැරඹුම් ඉතිහාසය ගබඩා කරන්න",
|
||||
"enabled_codecs": "සබල කර ඇති කෝඩෙක්ස් (බහු)",
|
||||
"minimize_description_default": "පෙරනිමි පරිදි සවිස්තරය සඟවන්න",
|
||||
"instances_list": "සේවාදායක ලැයිස්තුව",
|
||||
"instance_selection": "සේවාදායකය",
|
||||
"view_ssl_score": "SSL ලකුණු බලන්න",
|
||||
"search": "සොයන්න (Ctrl+K)",
|
||||
"loading": "පූරණය වෙමින්...",
|
||||
"hide_replies": "පිළිතුරු සඟවන්න",
|
||||
"load_more_replies": "තවත් පිළිතුරු පෙන්වන්න",
|
||||
"add_to_playlist": "වාදන ලැයිස්තුවට දමන්න",
|
||||
"create_playlist": "වාදන ලැයිස්තුව සාදන්න",
|
||||
"delete_playlist": "වාදන ලැයිස්තුව මකන්න",
|
||||
"select_playlist": "වාදන ලැයිස්තුවක් තෝරන්න",
|
||||
"please_select_playlist": "වාදන ලැයිස්තුවක් තෝරන්න",
|
||||
"delete_account": "ගිණුම මකන්න",
|
||||
"logout": "මෙම උපාංගයෙන් නික්මෙන්න",
|
||||
"minimize_recommendations_default": "පෙරනිමි පරිදි නිර්දේශ හකුළන්න",
|
||||
"invalidate_session": "සියළුම උපාංග නික්මවන්න",
|
||||
"clone_playlist": "වාදන ලැයිස්තුවේ අනුපිටපතක්",
|
||||
"download_as_txt": ".txt ලෙස බාගන්න",
|
||||
"reset_preferences": "අභිප්රේත නැවත සකසන්න",
|
||||
"backup_preferences": "අභිප්රේත උපස්ථ කරන්න",
|
||||
"restore_preferences": "අභිප්රේත ප්රත්යර්පණය කරන්න",
|
||||
"back_to_home": "ආපසු මුල් පිටුවට",
|
||||
"share": "බෙදාගන්න",
|
||||
"with_timecode": "කාල කේතය සමඟ බෙදා ගන්න",
|
||||
"piped_link": "පයිප්ඩ් සබැඳිය",
|
||||
"copy_link": "සබැඳියේ පිටපතක්",
|
||||
"time_code": "කාල කේතය (තත්පර වලින්)",
|
||||
"show_chapters": "පරිච්ඡේද",
|
||||
"status_page": "තත්වය",
|
||||
"source_code": "ප්රභව කේතය",
|
||||
"documentation": "ප්රලේඛනය",
|
||||
"reply_count": "පිළිතුරු {count}",
|
||||
"with_playlist": "වාදන ලැයිස්තුව සමඟ බෙදා ගන්න",
|
||||
"bookmark_playlist": "පොත්යොමුවක්",
|
||||
"show_watch_on_youtube": "යූටියුබ්හි නරඹන්න බොත්තම පෙන්වන්න",
|
||||
"filter": "පෙරහන",
|
||||
"instance_donations": "සේවාදායක පරිත්යාග",
|
||||
"instance_auth_selection": "සත්යතාව තහවුරු කිරීම සඳහා සේවාදායකයක් තේරීම",
|
||||
"view_subscriptions": "දායකත්ව බලන්න",
|
||||
"uses_api_from": "භාවිතා වන යෙ.ක්ර.මු. (API): ",
|
||||
"skip_intro": "විරාම/හඳුන්වාදීමේ සජීවිකරණය මඟ හරින්න",
|
||||
"skip_interaction": "අන්තර් ක්රියා මතක් කිරීම මඟ හරින්න (දායක වන්න)",
|
||||
"skip_non_music": "ගීත: ගීතය නොවන කොටස මඟ හරින්න",
|
||||
"remove_from_playlist": "වාදන ලැයිස්තුවෙන් ඉවතලන්න",
|
||||
"audio_only": "හඬ පමණි",
|
||||
"country_selection": "රට",
|
||||
"minimize_comments_default": "පෙරනිමි පරිදි අදහස් සඟවන්න",
|
||||
"clear_history": "ඉතිහාසය මකන්න",
|
||||
"disable_lbry": "ප්රචාරය සඳහා LBRY අබල කරන්න",
|
||||
"delete_playlist_video_confirm": "වාදන ලැයිස්තුවෙන් දෘශ්යකය ඉවත් කරන්නද?",
|
||||
"delete_playlist_confirm": "මෙම වාදන ලැයිස්තුව මකන්නද?",
|
||||
"minimize_chapters_default": "පෙරනිමි පරිදි පරිච්ඡේද හකුළන්න",
|
||||
"clone_playlist_success": "අනුපිටපතක් සෑදිණි!",
|
||||
"confirm_reset_preferences": "ඔබගේ අභිප්රේත නැවත සැකසීමට වුවමනා ද?",
|
||||
"follow_link": "සබැඳියට යන්න",
|
||||
"store_search_history": "සෙවුම් ඉතිහාසය ගබඩා කරන්න",
|
||||
"no_valid_playlists": "ගොනුවේ වලංගු වාදන ලැයිස්තු අඩංගු නොවේ!",
|
||||
"playlist_bookmarked": "පොත්යොමුවක් යෙදිණි",
|
||||
"enable_lbry_proxy": "LBRY සඳහා ප්රතියුක්තය සබල කරන්න",
|
||||
"different_auth_instance": "සත්යතාව තහවුරු කිරීම සඳහා වෙනත් සේවාදායකයක් භාවිතා කරන්න",
|
||||
"hide_watched": "සංග්රහයෙන් නැරඹූ දෘශ්යක සඟවන්න",
|
||||
"skip_button_only": "මඟහරින බොත්තම පෙන්වන්න",
|
||||
"skip_automatically": "ස්වයංක්රීයව",
|
||||
"skip_segment": "කොටස මඟ හරින්න",
|
||||
"min_segment_length": "අවම කොටස් දිග (තත්පර වලින්)",
|
||||
"show_less": "අඩුවෙන් පෙන්වන්න",
|
||||
"dismiss": "අයින් කරන්න",
|
||||
"autoplay_next_countdown": "ඊළඟ දෘශ්යකය තෙක් ගණන් කිරීම (තත්. වලින්)",
|
||||
"group_name": "සමූහයේ නම",
|
||||
"create_group": "සමූහය සාදන්න",
|
||||
"cancel": "අවලංගු",
|
||||
"okay": "හරි",
|
||||
"edit_playlist": "වාදන ලැයිස්තුව සංස්කරණය",
|
||||
"playlist_name": "වාදන ලැයිස්තුවේ නම",
|
||||
"playlist_description": "වාදන ලැයිස්තුවේ සවිස්තරය",
|
||||
"auto_display_captions": "උපසිරැසි ස්වයංක්රීයව පෙන්වන්න",
|
||||
"show_search_suggestions": "සෙවුම් යෝජනා පෙන්වන්න",
|
||||
"delete_automatically": "මෙයින් පසුව මකන්න",
|
||||
"generate_qrcode": "QR කේතයක් උත්පාදනය"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "{0} හි නරඹන්න"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "{author} විසින් අමුණන ලදී",
|
||||
"loading": "අදහස් පූරණය වෙමින්...",
|
||||
"disabled": "උඩුගත කරන්නා විසින් අදහස් අබල කර ඇත.",
|
||||
"user_disabled": "සැකසුම් හරහා අදහස් අබල කර ඇත."
|
||||
},
|
||||
"preferences": {
|
||||
"has_cdn": "CDN තිබේද?",
|
||||
"version": "අනුවාදය",
|
||||
"up_to_date": "යාවත්කාලීනද?",
|
||||
"instance_name": "සේවාදායකයේ නම",
|
||||
"registered_users": "ලියාපදිංචි පරිශ්රීලකයින්",
|
||||
"ssl_score": "SSL ලකුණු",
|
||||
"instance_locations": "සේවාදායකයේ ස්ථානය"
|
||||
},
|
||||
"login": {
|
||||
"username": "පරිශ්රීලක නාමය",
|
||||
"password": "මුරපදය"
|
||||
},
|
||||
"video": {
|
||||
"videos": "දෘශ්යක",
|
||||
"views": "බැලීම් {views}",
|
||||
"watched": "නැරඹුවා",
|
||||
"sponsor_segments": "අනුග්රාහක අංශ",
|
||||
"chapters": "පරිච්ඡේද",
|
||||
"shorts": "කෙටි දෘශ්යක",
|
||||
"ratings_disabled": "ශ්රේණිගත කිරීම් අබල කර ඇත",
|
||||
"live": "{0} සජීවී",
|
||||
"all": "සියල්ල",
|
||||
"category": "ප්රවර්ගය",
|
||||
"chapters_vertical": "සිරස්",
|
||||
"license": "බලපත්රය",
|
||||
"chapters_horizontal": "තිරස්"
|
||||
},
|
||||
"search": {
|
||||
"did_you_mean": "ඔබ අදහස් කළේ: {0}?",
|
||||
"videos": "යූටියුබ්: දෘශ්යක",
|
||||
"playlists": "යූටියුබි: වාදන ලැයිස්තු",
|
||||
"music_songs": "යූටියුබි ගීත: ගීත",
|
||||
"music_videos": "යූටියුබි ගීත: දෘශ්යක",
|
||||
"music_albums": "YT Music: ඇල්බම",
|
||||
"music_playlists": "යූටියුබි ගීත: වාදන ලැයිස්තු",
|
||||
"channels": "යූටියුබ්: නාලිකා",
|
||||
"all": "යූටියුබි: සියල්ල",
|
||||
"music_artists": "යූටියුබ් ගීත: කලාකරුවන්"
|
||||
},
|
||||
"info": {
|
||||
"page_not_found": "පිටුව හමු නොවිණි",
|
||||
"copied": "පිටපත් විය!",
|
||||
"cannot_copy": "පිටපත් නොවේ!",
|
||||
"local_storage": "මෙම ක්රියාමාර්ගයට ස්ථානීය-ආචයනය වුවමනාය, දත්තකඩ සබල කර තිබේද?",
|
||||
"register_no_email_note": "පරිශ්රීලක නාමය ලෙස වි-තැපෑලක් භාවිතය නිර්දේශ නොකෙරේ. ඉදිරියට යන්නද?",
|
||||
"preferences_note": "සටහන: ඔබගේ අතිරික්සුවේ ස්ථානීය ආචයනයේ අභිප්රේත සුරැකෙයි. අතිරික්සුවේ දත්ත මැකීමෙන් ඒවා අහිමි වනු ඇත.",
|
||||
"next_video_countdown": "ඊළඟ දෘශ්යකය තත්. {0} කින් වාදනය වේ",
|
||||
"days": "දවස් {amount}",
|
||||
"weeks": "සති {amount}",
|
||||
"hours": "පැය {amount}",
|
||||
"months": "මාස {amount}"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "දායක වූයේ: {0}"
|
||||
}
|
||||
}
|
@ -72,8 +72,6 @@
|
||||
"view_ssl_score": "Zobraziť SSL skóre",
|
||||
"filter": "Filter",
|
||||
"delete_playlist_video_confirm": "Odstrániť video zo zoznamu?",
|
||||
"rename_playlist": "Premenovať zoznam skladieb",
|
||||
"new_playlist_name": "Nový názov zoznamu skladieb",
|
||||
"share": "Zdieľať",
|
||||
"follow_link": "Nasledujte odkaz",
|
||||
"loading": "Načítavanie...",
|
||||
|
@ -7,7 +7,9 @@
|
||||
"ratings_disabled": "Оцене су онемогућене",
|
||||
"chapters": "Поглавља",
|
||||
"live": "{0} Уживо",
|
||||
"shorts": "Кратки видео снимци"
|
||||
"shorts": "Кратки видео снимци",
|
||||
"all": "Све",
|
||||
"category": "Категорија"
|
||||
},
|
||||
"actions": {
|
||||
"view_ssl_score": "Погледај SSL скор/оцену",
|
||||
@ -23,7 +25,7 @@
|
||||
"load_more_replies": "Учитај још одговора",
|
||||
"unsubscribe": "Прекини са праћењем - {count}",
|
||||
"auto": "Аутоматски",
|
||||
"search": "Претрага",
|
||||
"search": "Претрага (Ctrl+K)",
|
||||
"skip_non_music": "Прескочи делове где нема музике у музичким видео клиповима",
|
||||
"theme": "Теме",
|
||||
"audio_only": "Само звук",
|
||||
@ -98,21 +100,28 @@
|
||||
"status_page": "Статус",
|
||||
"instance_donations": "Донације инстанци",
|
||||
"show_chapters": "Поглавља",
|
||||
"rename_playlist": "Преименуј плејлисту",
|
||||
"with_timecode": "Подели са временским кодом",
|
||||
"piped_link": "Piped веза",
|
||||
"back_to_home": "Врати се на почетну",
|
||||
"follow_link": "Прати везу",
|
||||
"copy_link": "Копирај везу",
|
||||
"time_code": "Временски код (у секундама)",
|
||||
"new_playlist_name": "Ново име плејлисте",
|
||||
"minimize_comments_default": "Подразумевано умањи коментаре",
|
||||
"minimize_comments": "Умањи коментаре",
|
||||
"reply_count": "{count} одговора",
|
||||
"minimize_chapters_default": "Умањи поглавља подразумевано",
|
||||
"show_watch_on_youtube": "Прикажите \"Гредај на YouTube-у\" дугме",
|
||||
"no_valid_playlists": "Датотека не садржи важеће пописе снимака!",
|
||||
"with_playlist": "Делите са пописом снимака"
|
||||
"with_playlist": "Делите са пописом снимака",
|
||||
"playlist_bookmarked": "Обиљежено",
|
||||
"bookmark_playlist": "Биљежак",
|
||||
"show_less": "Прикажи мање",
|
||||
"skip_button_only": "Прикажи дугме за прескакање",
|
||||
"skip_automatically": "Аутоматски",
|
||||
"min_segment_length": "Најмања дужина сегмента (у секундама)",
|
||||
"skip_segment": "Прескочи сегмент",
|
||||
"dismiss": "Одбаци",
|
||||
"autoplay_next_countdown": "Подразумевано одбројавање до следећег видеа (у секундама)"
|
||||
},
|
||||
"preferences": {
|
||||
"instance_locations": "Локација инстанце",
|
||||
@ -151,7 +160,8 @@
|
||||
"instance": "Инстанца",
|
||||
"player": "Покретник",
|
||||
"livestreams": "Уживо преноси",
|
||||
"channels": "Канали"
|
||||
"channels": "Канали",
|
||||
"bookmarks": "Биљешци"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Закачено од {author}",
|
||||
@ -170,6 +180,8 @@
|
||||
"copied": "Копирано!",
|
||||
"cannot_copy": "Није могуће копирати!",
|
||||
"preferences_note": "Напомена: подешавања се чувају у локалној меморији вашег претраживача. Брисање података прегледача ће их ресетовати.",
|
||||
"local_storage": "Ова радња захтева локално складиште, да ли су колачићи омогућени ?"
|
||||
"local_storage": "Ова радња захтева локално складиште, да ли су колачићи омогућени ?",
|
||||
"register_no_email_note": "Коришћење е-поруке као корисничког имена се не препоручује. Желите ли ипак наставити?",
|
||||
"next_video_countdown": "Репродукује се следећи видео за {0}с"
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,12 @@
|
||||
"playlists": "Spellistor",
|
||||
"account": "Konto",
|
||||
"instance": "Instans",
|
||||
"player": "Spelare"
|
||||
"player": "Spelare",
|
||||
"bookmarks": "Bokmärken",
|
||||
"dearrow": "DeArrow",
|
||||
"livestreams": "Livesändningar",
|
||||
"channels": "Kanaler",
|
||||
"channel_groups": "Kanal Grupper"
|
||||
},
|
||||
"actions": {
|
||||
"subscribe": "Prenumerera - {count}",
|
||||
@ -46,18 +51,18 @@
|
||||
"store_watch_history": "Spara titthistorik",
|
||||
"instances_list": "Lista över instanser",
|
||||
"enabled_codecs": "Aktivera codecs (flera)",
|
||||
"import_from_json": "Importera från JSON/CSV",
|
||||
"donations": "Donationer",
|
||||
"import_from_json": "Importera från JSON",
|
||||
"donations": "Donationer till utveckling",
|
||||
"filter": "Filter",
|
||||
"hide_replies": "Dölj svar",
|
||||
"load_more_replies": "Ladda fler svar",
|
||||
"enable_sponsorblock": "Aktivera sponsorblockering",
|
||||
"skip_preview": "Hoppa över förhandsgranskning/sammanfattning",
|
||||
"autoplay_video": "Spela upp video automatiskt",
|
||||
"country_selection": "Val av land",
|
||||
"language_selection": "Val av språk",
|
||||
"country_selection": "Land",
|
||||
"language_selection": "Språk",
|
||||
"skip_non_music": "Hoppa över musik: Icke-musikaliskt avsnitt",
|
||||
"instance_selection": "Val av instans",
|
||||
"instance_selection": "Instans",
|
||||
"show_more": "Visa mer",
|
||||
"yes": "Ja",
|
||||
"no": "Nej",
|
||||
@ -67,7 +72,7 @@
|
||||
"show_recommendations": "Visa rekommendationer",
|
||||
"disable_lbry": "Inaktivera LBRY för strömning",
|
||||
"enable_lbry_proxy": "Aktivera proxy för LBRY",
|
||||
"search": "Sök",
|
||||
"search": "Sök (Ctrl+K)",
|
||||
"clear_history": "Rensa historik",
|
||||
"skip_filler_tangent": "Hoppa över påfyllningstangent",
|
||||
"skip_highlight": "Hoppa över höjdpunkt",
|
||||
@ -87,15 +92,61 @@
|
||||
"minimize_recommendations_default": "Minimera rekommendationer som standard",
|
||||
"invalidate_session": "Logga ut alla enheter",
|
||||
"different_auth_instance": "Använd en annan instans för autentisering",
|
||||
"instance_auth_selection": "Val av autentiseringsinstans",
|
||||
"instance_auth_selection": "Autentiseringsinstans",
|
||||
"download_as_txt": "Ladda ner som .txt",
|
||||
"reset_preferences": "Återställ inställningar",
|
||||
"confirm_reset_preferences": "Är du säker på att du vill återställa dina inställningar?",
|
||||
"backup_preferences": "Inställningar för säkerhetskopiering",
|
||||
"restore_preferences": "Återställa inställningar"
|
||||
"restore_preferences": "Återställa inställningar",
|
||||
"enable_dearrow": "Aktivera DeArrow",
|
||||
"autoplay_next_countdown": "Antal sekunder tills nästa video startar automatiskt",
|
||||
"minimize_comments_default": "Minimera kommentarer som standard",
|
||||
"show_watch_on_youtube": "Visa knappen \"Titta på YouTube\"",
|
||||
"back_to_home": "Tillbaka till startsidan",
|
||||
"delete_automatically": "Ta bort automatiskt efter",
|
||||
"with_timecode": "Dela med tidsstämpel",
|
||||
"reply_count": "{count} svar",
|
||||
"with_playlist": "Dela med spellista",
|
||||
"dismiss": "Avböj",
|
||||
"min_segment_length": "Minsta segmentlängd (i sekunder)",
|
||||
"skip_segment": "Hoppa över segment",
|
||||
"minimize_comments": "Minimera kommentarer",
|
||||
"show_less": "Visa mindre",
|
||||
"cancel": "Avbryt",
|
||||
"store_search_history": "Spara sökhistorik",
|
||||
"documentation": "Dokumentation",
|
||||
"okay": "Okej",
|
||||
"status_page": "Status",
|
||||
"minimize_chapters_default": "Minimera kapitel som standard",
|
||||
"time_code": "Tidsstämpel (i sekunder)",
|
||||
"hide_watched": "Dölj tittade videor i flödet",
|
||||
"share": "Dela",
|
||||
"show_chapters": "Kapitel",
|
||||
"source_code": "Källkod",
|
||||
"edit_playlist": "Redigera spellista",
|
||||
"playlist_name": "Spellistans namn",
|
||||
"playlist_description": "Beskrivning av spellista",
|
||||
"generate_qrcode": "Generera QR-kod",
|
||||
"chapters_layout_mobile": "Layout för kapitel på mobil",
|
||||
"piped_link": "Piped-länk",
|
||||
"follow_link": "Följ-länk",
|
||||
"copy_link": "Kopiera länk",
|
||||
"group_name": "Gruppnamn",
|
||||
"show_search_suggestions": "Visa sökförslag",
|
||||
"auto_display_captions": "Automatisk visning av textning",
|
||||
"bookmark_playlist": "Bokmärke",
|
||||
"instance_donations": "Instans donationer",
|
||||
"no_valid_playlists": "Filen innehåller inga giltiga spellistor!",
|
||||
"playlist_bookmarked": "Bokmärkt",
|
||||
"create_group": "Skapa grupp",
|
||||
"skip_button_only": "Visa hoppa över-knapp",
|
||||
"skip_automatically": "Automatiskt",
|
||||
"download_frame": "Ladda ner bildruta",
|
||||
"import_from_json_csv": "Importera från JSON/CSV"
|
||||
},
|
||||
"player": {
|
||||
"watch_on": "Titta på {0}"
|
||||
"watch_on": "Titta på {0}",
|
||||
"failed": "Misslyckades med felkod {0}, se loggar för mer information"
|
||||
},
|
||||
"preferences": {
|
||||
"instance_name": "Instansnamn",
|
||||
@ -108,7 +159,9 @@
|
||||
},
|
||||
"login": {
|
||||
"username": "Användarnamn",
|
||||
"password": "Lösenord"
|
||||
"password": "Lösenord",
|
||||
"password_confirm": "Bekräfta lösenord",
|
||||
"passwords_incorrect": "Lösenorden stämmer inte överens!"
|
||||
},
|
||||
"video": {
|
||||
"videos": "Videor",
|
||||
@ -118,7 +171,13 @@
|
||||
"ratings_disabled": "Betyg inaktiverade",
|
||||
"chapters": "Kapitel",
|
||||
"live": "{0} Live",
|
||||
"shorts": "Shorts"
|
||||
"shorts": "Shorts",
|
||||
"license": "Licens",
|
||||
"all": "Alla",
|
||||
"category": "Kategori",
|
||||
"chapters_horizontal": "Horisontell",
|
||||
"visibility": "Synlighet",
|
||||
"chapters_vertical": "Vertikal"
|
||||
},
|
||||
"comment": {
|
||||
"pinned_by": "Fäst av {author}",
|
||||
@ -135,12 +194,26 @@
|
||||
"all": "YouTube: Alla",
|
||||
"videos": "YouTube: Videor",
|
||||
"playlists": "YouTube: Spellistor",
|
||||
"music_songs": "YT Music: Låtar"
|
||||
"music_songs": "YT Music: Låtar",
|
||||
"music_artists": "YT Music: Artister"
|
||||
},
|
||||
"subscriptions": {
|
||||
"subscribed_channels_count": "Prenumererar på: {0}"
|
||||
},
|
||||
"information": {
|
||||
"preferences_note": "Observera: inställningar sparas i webbläsarens lokala lagring. Om du raderar dina webbläsardata återställs de."
|
||||
},
|
||||
"info": {
|
||||
"register_no_email_note": "Det rekommenderas inte att använda e-post som användarnamn. Fortsätt ändå?",
|
||||
"hours": "{amount} timma(r)",
|
||||
"preferences_note": "Obs: Inställningarna sparas i det lokala lagringsutrymmet i din webbläsare. Om du raderar dina webbläsardata återställs de.",
|
||||
"days": "{amount} dag(ar)",
|
||||
"weeks": "{amount} vecka/veckor",
|
||||
"months": "{amount} månad(er)",
|
||||
"next_video_countdown": "Spelar nästa video om {0}s",
|
||||
"cannot_copy": "Kan inte kopiera!",
|
||||
"page_not_found": "Sida hittas ej",
|
||||
"copied": "Kopierad!",
|
||||
"local_storage": "Det här kräver localStorage, är cookies aktiverat?"
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user