diff --git a/.babelrc b/.babelrc index abf4798b2..bca0e3c2c 100644 --- a/.babelrc +++ b/.babelrc @@ -4,8 +4,8 @@ "@babel/env", { "targets": { - "chrome": "106", - "node": "16.16.0" + "chrome": "122", + "node": "20.9.0" } } ] diff --git a/.eslintrc.js b/.eslintrc.js index 2729411b7..1846e7791 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,3 +1,8 @@ +const path = require('path') +const { readFileSync } = require('fs') + +const activeLocales = JSON.parse(readFileSync(path.join(__dirname, './static/locales/activeLocales.json'))) + module.exports = { // https://eslint.org/docs/user-guide/configuring#using-configuration-files-1 root: true, @@ -47,11 +52,12 @@ module.exports = { 'plugin:vue/recommended', 'standard', 'plugin:jsonc/recommended-with-json', - 'plugin:vuejs-accessibility/recommended' + 'plugin:vuejs-accessibility/recommended', + 'plugin:@intlify/vue-i18n/recommended' ], // https://eslint.org/docs/user-guide/configuring#configuring-plugins - plugins: ['vue', 'vuejs-accessibility', 'n', 'unicorn'], + plugins: ['vue', 'vuejs-accessibility', 'n', 'unicorn', '@intlify/vue-i18n'], rules: { 'space-before-function-paren': 'off', @@ -77,6 +83,40 @@ module.exports = { 'unicorn/no-array-push-push': 'error', 'unicorn/prefer-keyboard-event-key': 'error', 'unicorn/prefer-regexp-test': 'error', - 'unicorn/prefer-string-replace-all': 'error' + 'unicorn/prefer-string-replace-all': 'error', + '@intlify/vue-i18n/no-dynamic-keys': 'error', + // TODO: enable at a later date. currently disabled to prevent massive conflicts for initial PR + // '@intlify/vue-i18n/no-unused-keys': [ + // 'error', + // { + // extensions: ['.js', '.vue', 'yaml'] + // } + // ], + '@intlify/vue-i18n/no-duplicate-keys-in-locale': 'error', + '@intlify/vue-i18n/no-raw-text': [ + 'error', + { + attributes: { + '/.+/': [ + 'title', + 'aria-label', + 'aria-placeholder', + 'aria-roledescription', + 'aria-valuetext', + 'tooltip', + 'message' + ], + input: ['placeholder', 'value'], + img: ['alt'] + }, + ignoreText: ['-', '•', '/', 'YouTube', 'Invidious', 'FreeTube'] + } + ], + }, + settings: { + 'vue-i18n': { + localeDir: `./static/locales/{${activeLocales.join(',')}}.yaml`, + messageSyntaxVersion: '^8.0.0' + } } } diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 3ee6b6eaf..aef914ee3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -92,7 +92,7 @@ body: - Portable - .rpm - .zip - - .apk (Android, FreeTubeCordova Unofficial) + - .apk (FreeTubeAndroid Unofficial) - AUR (Unofficial) - Chocolatey (Unofficial) - Homebrew (Unofficial) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 26cd65aa8..65a5c0f0c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -8,7 +8,7 @@ contact_links: about: Ask and answer questions - name: Matrix Community url: https://matrix.to/#/+freetube:matrix.org - about: Join our Matrix chatroom - "Note: Bugs and Feature requests should be made on GitHub and not in the Matrix room" + about: 'Join our Matrix chatroom - "Note: Bugs and Feature requests should be made on GitHub and not in the Matrix room"' - name: Translate FreeTube url: https://hosted.weblate.org/engage/free-tube/ about: Help translate FreeTube on Weblate diff --git a/.github/issue-labeler.yml b/.github/issue-labeler.yml index 1d08f2788..38178571e 100644 --- a/.github/issue-labeler.yml +++ b/.github/issue-labeler.yml @@ -2,7 +2,7 @@ - '(visual bug)' 'B: Unofficial Download': - - '(AUR \(Unofficial\)|Chocolatey \(Unofficial\)|\.apk \(Android, FreeTubeCordova Unofficial\)|Homebrew \(Unofficial\)|PortableApps \(Unofficial\)|WAPT \(Unofficial\)|winget \(Unofficial\)|Scoop \(Unofficial\)|Snapcraft \(Unofficial\)|MPR \(Unofficial\)|Nix \(Unofficial\))' + - '(AUR \(Unofficial\)|Chocolatey \(Unofficial\)|\.apk \(FreeTubeAndroid Unofficial\)|Homebrew \(Unofficial\)|PortableApps \(Unofficial\)|WAPT \(Unofficial\)|winget \(Unofficial\)|Scoop \(Unofficial\)|Snapcraft \(Unofficial\)|MPR \(Unofficial\)|Nix \(Unofficial\))' 'B: keyboard control': - '(keyboard control not working)' diff --git a/.github/workflows/autoLabelDuplicate.yml b/.github/workflows/autoLabelDuplicate.yml index 4bbbc9b4c..56fa8681e 100644 --- a/.github/workflows/autoLabelDuplicate.yml +++ b/.github/workflows/autoLabelDuplicate.yml @@ -5,10 +5,10 @@ on: jobs: test: + if: github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER' runs-on: ubuntu-latest steps: - name: Check Comment Author - if: github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER' uses: Amwam/issue-comment-action@v1.3.1 with: keywords: '["duplicate of #", "duplicate of https://github.com/FreeTubeApp/FreeTube/issues/", "duplicate of https://github.com/FreeTubeApp/FreeTube/pulls/"]' diff --git a/.github/workflows/autoMerge.yml b/.github/workflows/autoMerge.yml index c979c7414..db334ad22 100644 --- a/.github/workflows/autoMerge.yml +++ b/.github/workflows/autoMerge.yml @@ -5,11 +5,11 @@ on: jobs: build: + if: ${{ !github.event.pull_request.draft && (contains(github.event.pull_request.base.ref, 'development') || contains(github.event.pull_request.base.ref, 'RC')) }} runs-on: ubuntu-latest steps: - name: Auto Merge PR - if: ${{ !github.event.pull_request.draft && (contains(github.event.pull_request.base.ref, 'development') || contains(github.event.pull_request.base.ref, 'RC')) }} run: | echo ${{ secrets.PUSH_TOKEN }} >> auth.txt gh auth login --with-token < auth.txt diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 569ded447..3bbef6630 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: build: strategy: matrix: - node-version: [18.x] + node-version: [20.x] runtime: - linux-x64 - linux-armv7l diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 53ea38937..a10f2f3e2 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -18,10 +18,12 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: - uses: actions/checkout@v4 - - name: Use Node.js 18.x + - name: Use Node.js 20.x uses: actions/setup-node@v4 with: - node-version: 18.x + node-version: 20.x cache: "yarn" - run: yarn run ci - run: yarn run lint + # let's verify that webpack is able to package the project + - run: yarn run pack diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 519492e79..87237a364 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: build: strategy: matrix: - node-version: [18.x] + node-version: [20.x] runtime: - linux-x64 - linux-armv7l diff --git a/README.md b/README.md index 0d478b917..196960948 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ FreeTube is an open source desktop YouTube player built with privacy in mind. Use YouTube without advertisements and prevent Google from tracking you with their cookies and JavaScript. -Available for Windows, Mac & Linux thanks to Electron. +Available for Windows (10 and later), Mac (macOS 10.15 and later) & Linux thanks to Electron.

Download FreeTube

@@ -21,17 +21,20 @@ Available for Windows, Mac & Linux thanks to Electron.

WebsiteBlogDocumentationFAQDiscussions


-Please note that FreeTube is currently in Beta. While it should work well for most users, there are still bugs and missing features that need to be addressed. If you have an idea or if you found a bug, please submit a [GitHub issue](https://github.com/FreeTubeApp/FreeTube/issues/new/choose) so that -we can track it. Please search [the existing issues](https://github.com/FreeTubeApp/FreeTube/issues) before submitting to -prevent duplicates! +> [!NOTE] +> FreeTube is currently in Beta. While it should work well for most users, there are still bugs and missing features that need to be addressed. +> +> If you have an idea or if you found a bug, please submit a [GitHub issue](https://github.com/FreeTubeApp/FreeTube/issues/new/choose) so that we can track it. Please search [the existing issues](https://github.com/FreeTubeApp/FreeTube/issues) before submitting to prevent duplicates! ## Screenshots ## How does it work? FreeTube uses a built in extractor to grab and serve data / videos. The [Invidious API](https://github.com/iv-org/invidious) can also optionally be used. FreeTube does not use any official APIs to obtain data. While YouTube can still see your video requests, it can no -longer track you using cookies or JavaScript. Your subscriptions and history are stored locally on your computer and never sent out. Using a VPN or Tor is highly recommended -to hide your IP while using FreeTube. +longer track you using cookies or JavaScript. Your subscriptions and history are stored locally on your computer and never sent out. + +> [!IMPORTANT] +> Using a VPN or Tor is highly recommended to hide your IP while using FreeTube. ## Features * Watch videos without ads @@ -59,16 +62,26 @@ to hide your IP while using FreeTube. * View most age restricted videos ### Browser Extension -FreeTube is supported by the [Privacy Redirect](https://github.com/SimonBrazell/privacy-redirect) and [LibRedirect](https://github.com/libredirect/libredirect) extensions, which will allow you to open YouTube links into FreeTube. You must enable the option within the advanced settings of the extension for it to work. +FreeTube is supported by the [Privacy Redirect](https://github.com/SimonBrazell/privacy-redirect) and [LibRedirect](https://github.com/libredirect/libredirect) extensions, which will allow you to open YouTube links into FreeTube. + +> [!IMPORTANT] +> You must enable the option within the advanced settings of the extension for it to work. * Download Privacy Redirect for [Firefox](https://addons.mozilla.org/en-US/firefox/addon/privacy-redirect/) or [Google Chrome](https://chrome.google.com/webstore/detail/privacy-redirect/pmcmeagblkinmogikoikkdjiligflglb). * Download LibRedirect for [Firefox](https://addons.mozilla.org/firefox/addon/libredirect/) or [Google Chrome](https://libredirect.github.io/download_chromium.html). -If you have issues with the extension working with FreeTube, please create an issue in this repository instead of the extension repository. This extension does not work on Linux portable builds! +> [!NOTE] +> This extension does not work on Linux portable builds! +> +> If you have issues with the extension working with FreeTube, please create an issue in this repository instead of the extension repository. ## Download Links ### Official Downloads + +> [!CAUTION] +> FreeTube is only supported on Windows 10 and later, macOS 10.15 and above, and various Linux distributions. Installing it on unsupported systems may result in unexpected issues. + * [GitHub Releases](https://github.com/FreeTubeApp/FreeTube/releases) * [FreeTube Website](https://freetubeapp.io/#download) @@ -76,18 +89,25 @@ If you have issues with the extension working with FreeTube, please create an is * Flatpak on Flathub: [Download](https://flathub.org/apps/details/io.freetubeapp.FreeTube) and [Source Code](https://github.com/flathub/io.freetubeapp.FreeTube) #### Automated Builds (Nightly / Weekly) +> [!WARNING] +> Use these builds at your own risk. These are pre-release versions and are only intended for people that want to test changes early and are willing to accept that things could break from one build to another. + Builds are automatically created from changes to our development branch via [GitHub Actions](https://github.com/FreeTubeApp/FreeTube/actions?query=workflow%3ABuild). -The first build with a green check mark is the latest build. You will need to have a GitHub account to download these builds. +The first build with a green check mark is the latest build. + +> [!IMPORTANT] +> You will need to have a GitHub account to download these builds. ### Unofficial Downloads -These builds are maintained by the community. While they should be safe, download at your own risk. There may be issues with using these versus the official builds. Any issues specific with these builds should be sent to their respective maintainer. Make sure u always try an [official download](https://github.com/freetubeapp/freetube/#official-downloads) before reporting your issue to us! +> [!WARNING] +> These builds are maintained by the community. While they should be safe, download at your own risk. There may be issues with using these versus the official builds. Any issues specific with these builds should be sent to their respective maintainer. Make sure u always try an [official download](https://github.com/freetubeapp/freetube/#official-downloads) before reporting your issue to us! * Arch User Repository (AUR): [Download](https://aur.archlinux.org/packages/freetube-bin/) * Chocolatey: [Download](https://chocolatey.org/packages/freetube/) -* FreeTubeCordova (FreeTube port for Android and PWA): [Download](https://github.com/MarmadileManteater/FreeTubeCordova/releases) and [Source Code](https://github.com/MarmadileManteater/FreeTubeCordova) +* FreeTubeAndroid (FreeTube port for Android and PWA): [Download](https://github.com/MarmadileManteater/FreeTubeAndroid/releases) and [Source Code](https://github.com/MarmadileManteater/FreeTubeAndroid) * Homebrew Formulae (Mac only): [Download](https://formulae.brew.sh/cask/freetube) @@ -106,14 +126,14 @@ These builds are maintained by the community. While they should be safe, downloa * Windows Package Manager (winget): [Usage](https://docs.microsoft.com/en-us/windows/package-manager/winget/) ## Contributing -If you like to get your hands dirty and want to contribute, we would love to -have your help. Send a pull request and someone will review your code. Please -follow the [Contribution -Guidelines](https://github.com/FreeTubeApp/FreeTube/blob/development/CONTRIBUTING.md) -before sending your pull request. - Thank you very much to the [People and Projects](https://docs.freetubeapp.io/credits/) that make FreeTube possible! +If you like to get your hands dirty and want to contribute, we would love to +have your help. Send a pull request and someone will review your code. + +> [!IMPORTANT] +> Please follow the [Contribution Guidelines](https://github.com/FreeTubeApp/FreeTube/blob/development/CONTRIBUTING.md) before sending your pull request. + ## Localization Translation status @@ -124,7 +144,10 @@ We are actively looking for translations! We use [Weblate](https://hosted.webla For the Linux Flatpak, the desktop entry comment string can be translated at our [Flatpak repository](https://github.com/flathub/io.freetubeapp.FreeTube/blob/master/io.freetubeapp.FreeTube.desktop). ## Contact -If you ever have any questions, feel free to ask it on our [Discussions](https://github.com/FreeTubeApp/FreeTube/discussions) page. Alternatively, you can email us at FreeTubeApp@protonmail.com or you can join our [Matrix Community](https://matrix.to/#/+freetube:matrix.org). Don't forget to check out the [rules](https://docs.freetubeapp.io/community/matrix/) before joining. +If you ever have any questions, feel free to ask it on our [Discussions](https://github.com/FreeTubeApp/FreeTube/discussions) page. Alternatively, you can email us at FreeTubeApp@protonmail.com or you can join our [Matrix Community](https://matrix.to/#/+freetube:matrix.org). + +> [!IMPORTANT] +> Don't forget to check out the [rules](https://docs.freetubeapp.io/community/matrix/) before joining. ## Donate If you enjoy using FreeTube, you're welcome to leave a donation using the following methods. @@ -135,7 +158,10 @@ If you enjoy using FreeTube, you're welcome to leave a donation using the follow * Monero Address: `48WyAPdjwc6VokeXACxSZCFeKEXBiYPV6GjfvBsfg4CrUJ95LLCQSfpM9pvNKy5GE5H4hNaw99P8RZyzmaU9kb1pD7kzhCB` -While your donations are much appreciated, only donate if you really want to. Donations are used for keeping the website up and running and eventual code signing costs. If you are using the Invidious API then we recommend that you donate to the instance that you use. You can also donate to the [Invidious team](https://invidious.io/donate/) or the [Local API developer](https://github.com/sponsors/LuanRT). +While your donations are much appreciated, only donate if you really want to. Donations are used for keeping the website up and running and eventual code signing costs. + +> [!TIP] +> If you are using the Invidious API then we recommend that you donate to the instance that you use. You can also donate to the [Invidious team](https://invidious.io/donate/) or the [Local API developer](https://github.com/sponsors/LuanRT). ## License [![GNU AGPLv3 Image](https://www.gnu.org/graphics/agplv3-155x51.png)](https://www.gnu.org/licenses/agpl-3.0.html) diff --git a/_scripts/webpack.main.config.js b/_scripts/webpack.main.config.js index 0f3c706c6..0358f7919 100644 --- a/_scripts/webpack.main.config.js +++ b/_scripts/webpack.main.config.js @@ -56,7 +56,7 @@ if (!isDevMode) { to: path.join(__dirname, '../dist/static'), globOptions: { dot: true, - ignore: ['**/.*', '**/locales/**', '**/pwabuilder-sw.js', '**/dashFiles/**', '**/storyboards/**'], + ignore: ['**/.*', '**/locales/**', '**/pwabuilder-sw.js', '**/manifest.json', '**/dashFiles/**', '**/storyboards/**'], }, }, ] diff --git a/_scripts/webpack.renderer.config.js b/_scripts/webpack.renderer.config.js index 5cb371e8a..18d778c89 100644 --- a/_scripts/webpack.renderer.config.js +++ b/_scripts/webpack.renderer.config.js @@ -119,6 +119,7 @@ const config = { new webpack.DefinePlugin({ 'process.env.IS_ELECTRON': true, 'process.env.IS_ELECTRON_MAIN': false, + 'process.env.SUPPORTS_LOCAL_API': true, 'process.env.LOCALE_NAMES': JSON.stringify(processLocalesPlugin.localeNames), 'process.env.GEOLOCATION_NAMES': JSON.stringify(readdirSync(path.join(__dirname, '..', 'static', 'geolocations')).map(filename => filename.replace('.json', ''))), 'process.env.SWIPER_VERSION': `'${swiperVersion}'` @@ -126,10 +127,7 @@ const config = { new HtmlWebpackPlugin({ excludeChunks: ['processTaskWorker'], filename: 'index.html', - template: path.resolve(__dirname, '../src/index.ejs'), - nodeModules: isDevMode - ? path.resolve(__dirname, '../node_modules') - : false, + template: path.resolve(__dirname, '../src/index.ejs') }), new VueLoaderPlugin(), new MiniCssExtractPlugin({ diff --git a/_scripts/webpack.web.config.js b/_scripts/webpack.web.config.js index 5113f06a7..0badc63a7 100644 --- a/_scripts/webpack.web.config.js +++ b/_scripts/webpack.web.config.js @@ -116,6 +116,7 @@ const config = { new webpack.DefinePlugin({ 'process.env.IS_ELECTRON': false, 'process.env.IS_ELECTRON_MAIN': false, + 'process.env.SUPPORTS_LOCAL_API': false, 'process.env.SWIPER_VERSION': `'${swiperVersion}'`, // video.js' vhs-utils supports both atob() in web browsers and Buffer in node @@ -136,8 +137,7 @@ const config = { new HtmlWebpackPlugin({ excludeChunks: ['processTaskWorker'], filename: 'index.html', - template: path.resolve(__dirname, '../src/index.ejs'), - nodeModules: false, + template: path.resolve(__dirname, '../src/index.ejs') }), new VueLoaderPlugin(), new MiniCssExtractPlugin({ diff --git a/package.json b/package.json index d86e68a44..052bd7086 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "freetube", "productName": "FreeTube", "description": "A private YouTube client", - "version": "0.19.1", + "version": "0.20.0", "license": "AGPL-3.0-or-later", "main": "./dist/main.js", "private": true, @@ -25,7 +25,7 @@ "build-release": "node _scripts/build.js", "build-release:arm64": "node _scripts/build.js arm64", "build-release:arm32": "node _scripts/build.js arm32", - "clean": "rimraf build/ static/dashFiles/ dist/ static/storyboards/", + "clean": "rimraf build/ dist/", "debug": "run-s rebuild:electron debug-runner", "debug-runner": "node _scripts/dev-runner.js --remote-debug", "dev": "run-s rebuild:electron dev-runner", @@ -53,9 +53,9 @@ "ci": "yarn install --silent --frozen-lockfile" }, "dependencies": { - "@fortawesome/fontawesome-svg-core": "^6.5.1", - "@fortawesome/free-brands-svg-icons": "^6.5.1", - "@fortawesome/free-solid-svg-icons": "^6.5.1", + "@fortawesome/fontawesome-svg-core": "^6.5.2", + "@fortawesome/free-brands-svg-icons": "^6.5.2", + "@fortawesome/free-solid-svg-icons": "^6.5.2", "@fortawesome/vue-fontawesome": "^2.0.10", "@seald-io/nedb": "^4.0.4", "@silvermine/videojs-quality-selector": "^1.3.1", @@ -65,7 +65,7 @@ "marked": "^12.0.1", "path-browserify": "^1.0.1", "process": "^0.11.10", - "swiper": "^11.0.7", + "swiper": "^11.1.0", "video.js": "7.21.5", "videojs-contrib-quality-levels": "^3.0.0", "videojs-http-source-selector": "^1.1.6", @@ -77,19 +77,20 @@ "vue-observe-visibility": "^1.0.0", "vue-router": "^3.6.5", "vuex": "^3.6.2", - "youtubei.js": "^9.1.0" + "youtubei.js": "^9.2.0" }, "devDependencies": { - "@babel/core": "^7.24.3", + "@babel/core": "^7.24.4", "@babel/eslint-parser": "^7.24.1", "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/preset-env": "^7.24.3", + "@babel/preset-env": "^7.24.4", "@double-great/stylelint-a11y": "^3.0.2", + "@intlify/eslint-plugin-vue-i18n": "^2.0.0", "babel-loader": "^9.1.3", "copy-webpack-plugin": "^12.0.2", - "css-loader": "^6.10.0", + "css-loader": "^7.0.0", "css-minimizer-webpack-plugin": "^6.0.0", - "electron": "^29.1.5", + "electron": "^29.2.0", "electron-builder": "^24.13.3", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", @@ -100,22 +101,22 @@ "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-promise": "^6.1.1", "eslint-plugin-unicorn": "^51.0.1", - "eslint-plugin-vue": "^9.23.0", + "eslint-plugin-vue": "^9.24.0", "eslint-plugin-vuejs-accessibility": "^2.2.1", "eslint-plugin-yml": "^1.13.2", "html-webpack-plugin": "^5.6.0", "js-yaml": "^4.1.0", "json-minimizer-webpack-plugin": "^5.0.0", - "lefthook": "^1.6.7", + "lefthook": "^1.6.8", "mini-css-extract-plugin": "^2.8.1", "npm-run-all": "^4.1.5", "postcss": "^8.4.38", "postcss-scss": "^4.0.9", "prettier": "^2.8.8", "rimraf": "^5.0.5", - "sass": "^1.72.0", + "sass": "^1.74.1", "sass-loader": "^14.1.1", - "stylelint": "^16.3.0", + "stylelint": "^16.3.1", "stylelint-config-sass-guidelines": "^11.1.0", "stylelint-config-standard": "^36.0.0", "stylelint-high-performance-animation": "^1.10.0", diff --git a/src/constants.js b/src/constants.js index b281fb168..322472503 100644 --- a/src/constants.js +++ b/src/constants.js @@ -23,7 +23,10 @@ const IpcChannels = { SYNC_SETTINGS: 'sync-settings', SYNC_HISTORY: 'sync-history', SYNC_PROFILES: 'sync-profiles', - SYNC_PLAYLISTS: 'sync-playlists' + SYNC_PLAYLISTS: 'sync-playlists', + + GET_REPLACE_HTTP_CACHE: 'get-replace-http-cache', + TOGGLE_REPLACE_HTTP_CACHE: 'toggle-replace-http-cache' } const DBActions = { diff --git a/src/index.ejs b/src/index.ejs index 1a224ca4a..40f7075a1 100644 --- a/src/index.ejs +++ b/src/index.ejs @@ -9,13 +9,6 @@ <% } %> - <% if (htmlWebpackPlugin.options.nodeModules) { %> - - <% } %> diff --git a/src/main/index.js b/src/main/index.js index 96ddd311e..73ca1d791 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -10,6 +10,7 @@ import { IpcChannels, DBActions, SyncEvents } from '../constants' import baseHandlers from '../datastores/handlers/base' import { extractExpiryTimestamp, ImageCache } from './ImageCache' import { existsSync } from 'fs' +import asyncFs from 'fs/promises' import packageDetails from '../../package.json' @@ -177,7 +178,8 @@ function runApp() { // command line switches need to be added before the app ready event first // that means we can't use the normal settings system as that is asynchronous, // doing it synchronously ensures that we add it before the event fires - const replaceHttpCache = existsSync(`${app.getPath('userData')}/experiment-replace-http-cache`) + const REPLACE_HTTP_CACHE_PATH = `${app.getPath('userData')}/experiment-replace-http-cache` + const replaceHttpCache = existsSync(REPLACE_HTTP_CACHE_PATH) if (replaceHttpCache) { // the http cache causes excessive disk usage during video playback // we've got a custom image cache to make up for disabling the http cache @@ -662,7 +664,7 @@ function runApp() { } }) - ipcMain.once('relaunchRequest', () => { + function relaunch() { if (process.env.NODE_ENV === 'development') { app.exit(parseInt(process.env.FREETUBE_RELAUNCH_EXIT_CODE)) return @@ -693,6 +695,10 @@ function runApp() { } app.quit() + } + + ipcMain.once('relaunchRequest', () => { + relaunch() }) nativeTheme.on('updated', () => { @@ -780,6 +786,22 @@ function runApp() { child.unref() }) + ipcMain.handle(IpcChannels.GET_REPLACE_HTTP_CACHE, () => { + return replaceHttpCache + }) + + ipcMain.once(IpcChannels.TOGGLE_REPLACE_HTTP_CACHE, async () => { + if (replaceHttpCache) { + await asyncFs.rm(REPLACE_HTTP_CACHE_PATH) + } else { + // create an empty file + const handle = await asyncFs.open(REPLACE_HTTP_CACHE_PATH, 'w') + await handle.close() + } + + relaunch() + }) + // ************************************************* // // DB related IPC calls // *********** // diff --git a/src/renderer/App.js b/src/renderer/App.js index bd553fb87..25af2892b 100644 --- a/src/renderer/App.js +++ b/src/renderer/App.js @@ -15,6 +15,7 @@ import { marked } from 'marked' import { IpcChannels } from '../constants' import packageDetails from '../../package.json' import { openExternalLink, openInternalPath, showToast } from './helpers/utils' +import { translateWindowTitle } from './helpers/strings' let ipcRenderer = null @@ -77,14 +78,13 @@ export default defineComponent({ return this.$store.getters.getShowCreatePlaylistPrompt }, windowTitle: function () { - const routeTitle = this.$route.meta.title - if (routeTitle !== 'Channel' && routeTitle !== 'Watch' && routeTitle !== 'Hashtag') { - let title = - this.$route.meta.path === '/home' - ? packageDetails.productName - : `${this.$t(this.$route.meta.title)} - ${packageDetails.productName}` + const routePath = this.$route.path + if (!routePath.startsWith('/channel/') && !routePath.startsWith('/watch/') && !routePath.startsWith('/hashtag/')) { + let title = translateWindowTitle(this.$route.meta.title, this.$i18n) if (!title) { title = packageDetails.productName + } else { + title = `${title} - ${packageDetails.productName}` } return title } else { @@ -466,12 +466,7 @@ export default defineComponent({ default: { // Unknown URL type - let message = 'Unknown YouTube url type, cannot be opened in app' - if (this.$te(message) && this.$t(message) !== '') { - message = this.$t(message) - } - - showToast(message) + showToast(this.$t('Unknown YouTube url type, cannot be opened in app')) } } }) diff --git a/src/renderer/components/data-settings/data-settings.js b/src/renderer/components/data-settings/data-settings.js index fac608c4b..9cda4bad1 100644 --- a/src/renderer/components/data-settings/data-settings.js +++ b/src/renderer/components/data-settings/data-settings.js @@ -520,7 +520,7 @@ export default defineComponent({ ] } - await this.promptAndWriteToFile(options, subscriptionsDb, 'Subscriptions have been successfully exported') + await this.promptAndWriteToFile(options, subscriptionsDb, this.$t('Settings.Data Settings.Subscriptions have been successfully exported')) }, exportYouTubeSubscriptions: async function () { @@ -573,7 +573,7 @@ export default defineComponent({ return object }) - await this.promptAndWriteToFile(options, JSON.stringify(subscriptionsObject), 'Subscriptions have been successfully exported') + await this.promptAndWriteToFile(options, JSON.stringify(subscriptionsObject), this.$t('Settings.Data Settings.Subscriptions have been successfully exported')) }, exportOpmlYouTubeSubscriptions: async function () { @@ -601,7 +601,7 @@ export default defineComponent({ opmlData += '' - await this.promptAndWriteToFile(options, opmlData, 'Subscriptions have been successfully exported') + await this.promptAndWriteToFile(options, opmlData, this.$t('Settings.Data Settings.Subscriptions have been successfully exported')) }, exportCsvYouTubeSubscriptions: async function () { @@ -628,7 +628,7 @@ export default defineComponent({ }) exportText += '\n' - await this.promptAndWriteToFile(options, exportText, 'Subscriptions have been successfully exported') + await this.promptAndWriteToFile(options, exportText, this.$t('Settings.Data Settings.Subscriptions have been successfully exported')) }, exportNewPipeSubscriptions: async function () { @@ -662,7 +662,7 @@ export default defineComponent({ newPipeObject.subscriptions.push(subscription) }) - await this.promptAndWriteToFile(options, JSON.stringify(newPipeObject), 'Subscriptions have been successfully exported') + await this.promptAndWriteToFile(options, JSON.stringify(newPipeObject), this.$t('Settings.Data Settings.Subscriptions have been successfully exported')) }, importHistory: async function () { @@ -856,7 +856,7 @@ export default defineComponent({ ] } - await this.promptAndWriteToFile(options, historyDb, 'All watched history has been successfully exported') + await this.promptAndWriteToFile(options, historyDb, this.$t('Settings.Data Settings.All watched history has been successfully exported')) }, importPlaylists: async function () { @@ -1035,7 +1035,7 @@ export default defineComponent({ return JSON.stringify(playlist) }).join('\n') + '\n'// a trailing line is expected - await this.promptAndWriteToFile(options, playlistsDb, 'All playlists has been successfully exported') + await this.promptAndWriteToFile(options, playlistsDb, this.$t('Settings.Data Settings.All playlists has been successfully exported')) }, exportPlaylistsForOlderVersionsSometimes: function () { @@ -1084,7 +1084,7 @@ export default defineComponent({ }) }) - await this.promptAndWriteToFile(options, JSON.stringify([favoritesPlaylistData]), 'All playlists has been successfully exported') + await this.promptAndWriteToFile(options, JSON.stringify([favoritesPlaylistData]), this.$t('Settings.Data Settings.All playlists has been successfully exported')) }, convertOldFreeTubeFormatToNew(oldData) { @@ -1094,7 +1094,7 @@ export default defineComponent({ for (const profile of channel.profile) { let index = convertedData.findIndex(p => p.name === profile.value) if (index === -1) { // profile doesn't exist yet - const randomBgColor = getRandomColor() + const randomBgColor = getRandomColor().value const contrastyTextColor = calculateColorLuminance(randomBgColor) convertedData.push({ name: profile.value, @@ -1118,7 +1118,7 @@ export default defineComponent({ return convertedData }, - promptAndWriteToFile: async function (saveOptions, content, successMessageKeySuffix) { + promptAndWriteToFile: async function (saveOptions, content, successMessage) { const response = await showSaveDialog(saveOptions) if (response.canceled || response.filePath === '') { // User canceled the save dialog @@ -1133,7 +1133,7 @@ export default defineComponent({ return } - showToast(this.$t(`Settings.Data Settings.${successMessageKeySuffix}`)) + showToast(successMessage) }, getChannelInfoInvidious: function (channelId) { @@ -1152,7 +1152,7 @@ export default defineComponent({ copyToClipboard(err) }) - if (process.env.IS_ELECTRON && this.backendFallback && this.backendPreference === 'invidious') { + if (process.env.SUPPORTS_LOCAL_API && this.backendFallback && this.backendPreference === 'invidious') { showToast(this.$t('Falling back to Local API')) resolve(this.getChannelInfoLocal(channelId)) } else { @@ -1182,7 +1182,7 @@ export default defineComponent({ }) if (this.backendFallback && this.backendPreference === 'local') { - showToast(this.$t('Falling back to the Invidious API')) + showToast(this.$t('Falling back to Invidious API')) return await this.getChannelInfoInvidious(channelId) } else { return [] diff --git a/src/renderer/components/experimental-settings/experimental-settings.js b/src/renderer/components/experimental-settings/experimental-settings.js index b4d5e8923..1c313c866 100644 --- a/src/renderer/components/experimental-settings/experimental-settings.js +++ b/src/renderer/components/experimental-settings/experimental-settings.js @@ -1,11 +1,9 @@ -import fs from 'fs/promises' import { defineComponent } from 'vue' import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue' import FtFlexBox from '../ft-flex-box/ft-flex-box.vue' import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue' import FtPrompt from '../ft-prompt/ft-prompt.vue' -import { pathExists } from '../../helpers/filesystem' -import { getUserDataPath } from '../../helpers/utils' +import { IpcChannels } from '../../../constants' export default defineComponent({ name: 'ExperimentalSettings', @@ -19,19 +17,16 @@ export default defineComponent({ return { replaceHttpCacheLoading: true, replaceHttpCache: false, - replaceHttpCachePath: '', showRestartPrompt: false } }, - mounted: function () { - getUserDataPath().then((userData) => { - this.replaceHttpCachePath = `${userData}/experiment-replace-http-cache` + mounted: async function () { + if (process.env.IS_ELECTRON) { + const { ipcRenderer } = require('electron') + this.replaceHttpCache = await ipcRenderer.invoke(IpcChannels.GET_REPLACE_HTTP_CACHE) + } - pathExists(this.replaceHttpCachePath).then((exists) => { - this.replaceHttpCache = exists - this.replaceHttpCacheLoading = false - }) - }) + this.replaceHttpCacheLoading = false }, methods: { handleRestartPrompt: function (value) { @@ -39,7 +34,7 @@ export default defineComponent({ this.showRestartPrompt = true }, - handleReplaceHttpCache: async function (value) { + handleReplaceHttpCache: function (value) { this.showRestartPrompt = false if (value === null || value === 'no') { @@ -47,16 +42,10 @@ export default defineComponent({ return } - if (this.replaceHttpCache) { - // create an empty file - const handle = await fs.open(this.replaceHttpCachePath, 'w') - await handle.close() - } else { - await fs.rm(this.replaceHttpCachePath) + if (process.env.IS_ELECTRON) { + const { ipcRenderer } = require('electron') + ipcRenderer.send(IpcChannels.TOGGLE_REPLACE_HTTP_CACHE) } - - const { ipcRenderer } = require('electron') - ipcRenderer.send('relaunchRequest') } } }) diff --git a/src/renderer/components/external-player-settings/external-player-settings.js b/src/renderer/components/external-player-settings/external-player-settings.js index d6662a9f1..d9e30a2b5 100644 --- a/src/renderer/components/external-player-settings/external-player-settings.js +++ b/src/renderer/components/external-player-settings/external-player-settings.js @@ -21,9 +21,15 @@ export default defineComponent({ computed: { externalPlayerNames: function () { const fallbackNames = this.$store.getters.getExternalPlayerNames - const nameTranslationKeys = this.$store.getters.getExternalPlayerNameTranslationKeys + const translations = [{ + name: 'None', + translatedValue: this.$t('Settings.External Player Settings.Players.None.Name') + }] - return nameTranslationKeys.map((translationKey, idx) => this.$te(translationKey) ? this.$t(translationKey) : fallbackNames[idx]) + return fallbackNames.map((name) => { + const translation = translations.find(e => e.name === name) + return translation ? translation.translatedValue : name + }) }, externalPlayerValues: function () { return this.$store.getters.getExternalPlayerValues diff --git a/src/renderer/components/ft-age-restricted/ft-age-restricted.js b/src/renderer/components/ft-age-restricted/ft-age-restricted.js index c9cd917bc..112d963f7 100644 --- a/src/renderer/components/ft-age-restricted/ft-age-restricted.js +++ b/src/renderer/components/ft-age-restricted/ft-age-restricted.js @@ -23,7 +23,7 @@ export default defineComponent({ return this.$t('Age Restricted.This channel is age restricted') } - return this.$t('Age Restricted.This video is age restricted:') + return this.$t('Age Restricted.This video is age restricted') } } }) diff --git a/src/renderer/components/ft-community-post/ft-community-post.js b/src/renderer/components/ft-community-post/ft-community-post.js index 6be036209..51fa39bb1 100644 --- a/src/renderer/components/ft-community-post/ft-community-post.js +++ b/src/renderer/components/ft-community-post/ft-community-post.js @@ -95,7 +95,7 @@ export default defineComponent({ this.postText = 'Shared post' this.type = 'text' let authorThumbnails = ['', 'https://yt3.ggpht.com/ytc/AAUvwnjm-0qglHJkAHqLFsCQQO97G7cCNDuDLldsrn25Lg=s88-c-k-c0x00ffffff-no-rj'] - if (!process.env.IS_ELECTRON || this.backendPreference === 'invidious') { + if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious') { authorThumbnails = authorThumbnails.map(thumbnail => { thumbnail.url = youtubeImageUrlToInvidious(thumbnail.url) return thumbnail @@ -106,7 +106,7 @@ export default defineComponent({ } this.postText = autolinker.link(this.data.postText) const authorThumbnails = deepCopy(this.data.authorThumbnails) - if (!process.env.IS_ELECTRON || this.backendPreference === 'invidious') { + if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious') { authorThumbnails.forEach(thumbnail => { thumbnail.url = youtubeImageUrlToInvidious(thumbnail.url) }) diff --git a/src/renderer/components/ft-list-channel/ft-list-channel.scss b/src/renderer/components/ft-list-channel/ft-list-channel.scss index 9ceb65342..4fa0fe962 100644 --- a/src/renderer/components/ft-list-channel/ft-list-channel.scss +++ b/src/renderer/components/ft-list-channel/ft-list-channel.scss @@ -1,5 +1,44 @@ @use '../../scss-partials/_ft-list-item'; +.ft-list-channel { + &.grid { + align-items: center; + text-align: center; + + .infoAndSubscribe { + flex-flow: column wrap; + align-items: center; + + .info { + margin-block-end: 12px; + + .infoLine { + text-align: center; + } + } + } + } + + &.list { + .infoAndSubscribe { + flex-flow: row wrap; + justify-content: center; + + .channelSubscribeButton { + margin-block: auto; + margin-inline: 7px; + } + } + } +} + +.infoAndSubscribe { + display: flex; + flex-flow: row wrap; + justify-content: center; + inline-size: 100%; +} + .handle { color: inherit; text-decoration: none; diff --git a/src/renderer/components/ft-list-video-numbered/ft-list-video-numbered.js b/src/renderer/components/ft-list-video-numbered/ft-list-video-numbered.js index 9ed32bb8e..e4fe2d7d6 100644 --- a/src/renderer/components/ft-list-video-numbered/ft-list-video-numbered.js +++ b/src/renderer/components/ft-list-video-numbered/ft-list-video-numbered.js @@ -83,7 +83,8 @@ export default defineComponent({ data: function () { return { visible: false, - show: true + show: true, + stopWatchingInitialVisibleState: null } }, computed: { @@ -111,13 +112,29 @@ export default defineComponent({ }, created() { this.visible = this.initialVisibleState + + if (!this.initialVisibleState) { + this.stopWatchingInitialVisibleState = this.$watch('initialVisibleState', (newValue) => { + this.visible = newValue + this.stopWatchingInitialVisibleState() + this.stopWatchingInitialVisibleState = null + }) + } }, methods: { onVisibilityChanged: function (visible) { if (visible && this.shouldBeVisible) { this.visible = visible + if (this.stopWatchingInitialVisibleState) { + this.stopWatchingInitialVisibleState() + this.stopWatchingInitialVisibleState = null + } } else if (visible) { this.show = false + if (this.stopWatchingInitialVisibleState) { + this.stopWatchingInitialVisibleState() + this.stopWatchingInitialVisibleState = null + } } } } diff --git a/src/renderer/components/ft-list-video-numbered/ft-list-video-numbered.vue b/src/renderer/components/ft-list-video-numbered/ft-list-video-numbered.vue index 745a704fe..4a6c2f889 100644 --- a/src/renderer/components/ft-list-video-numbered/ft-list-video-numbered.vue +++ b/src/renderer/components/ft-list-video-numbered/ft-list-video-numbered.vue @@ -1,10 +1,10 @@ diff --git a/src/renderer/components/subscriptions-community/subscriptions-community.js b/src/renderer/components/subscriptions-community/subscriptions-community.js index d3042f919..1c17cf6f5 100644 --- a/src/renderer/components/subscriptions-community/subscriptions-community.js +++ b/src/renderer/components/subscriptions-community/subscriptions-community.js @@ -125,7 +125,7 @@ export default defineComponent({ const postListFromRemote = (await Promise.all(channelsToLoadFromRemote.map(async (channel) => { let posts = [] - if (!process.env.IS_ELECTRON || this.backendPreference === 'invidious') { + if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious') { posts = await this.getChannelPostsInvidious(channel) } else { posts = await this.getChannelPostsLocal(channel) @@ -229,7 +229,7 @@ export default defineComponent({ showToast(`${errorMessage}: ${err}`, 10000, () => { copyToClipboard(err) }) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { showToast(this.$t('Falling back to Local API')) resolve(this.getChannelPostsLocal(channel)) } else { diff --git a/src/renderer/components/subscriptions-live/subscriptions-live.js b/src/renderer/components/subscriptions-live/subscriptions-live.js index 2877fe4d1..e13daf3ce 100644 --- a/src/renderer/components/subscriptions-live/subscriptions-live.js +++ b/src/renderer/components/subscriptions-live/subscriptions-live.js @@ -135,7 +135,7 @@ export default defineComponent({ let videos = [] let name, thumbnailUrl - if (!process.env.IS_ELECTRON || this.backendPreference === 'invidious') { + if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious') { if (useRss) { ({ videos, name, thumbnailUrl } = await this.getChannelLiveInvidiousRSS(channel)) } else { @@ -315,7 +315,7 @@ export default defineComponent({ resolve(this.getChannelLiveInvidiousRSS(channel, failedAttempts + 1)) break case 1: - if (process.env.IS_ELECTRON && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendFallback) { showToast(this.$t('Falling back to Local API')) resolve(this.getChannelLiveLocal(channel, failedAttempts + 1)) } else { @@ -360,7 +360,7 @@ export default defineComponent({ case 0: return this.getChannelLiveInvidious(channel, failedAttempts + 1) case 1: - if (process.env.IS_ELECTRON && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendFallback) { showToast(this.$t('Falling back to Local API')) return this.getChannelLiveLocalRSS(channel, failedAttempts + 1) } else { diff --git a/src/renderer/components/subscriptions-shorts/subscriptions-shorts.js b/src/renderer/components/subscriptions-shorts/subscriptions-shorts.js index 9a3c45c3c..062da5a21 100644 --- a/src/renderer/components/subscriptions-shorts/subscriptions-shorts.js +++ b/src/renderer/components/subscriptions-shorts/subscriptions-shorts.js @@ -120,7 +120,7 @@ export default defineComponent({ let videos = [] let name - if (!process.env.IS_ELECTRON || this.backendPreference === 'invidious') { + if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious') { ({ videos, name } = await this.getChannelShortsInvidious(channel)) } else { ({ videos, name } = await this.getChannelShortsLocal(channel)) @@ -234,7 +234,7 @@ export default defineComponent({ }) switch (failedAttempts) { case 0: - if (process.env.IS_ELECTRON && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendFallback) { showToast(this.$t('Falling back to Local API')) return this.getChannelShortsLocal(channel, failedAttempts + 1) } else { diff --git a/src/renderer/components/subscriptions-videos/subscriptions-videos.js b/src/renderer/components/subscriptions-videos/subscriptions-videos.js index 11ea86f6b..599fbb5f3 100644 --- a/src/renderer/components/subscriptions-videos/subscriptions-videos.js +++ b/src/renderer/components/subscriptions-videos/subscriptions-videos.js @@ -135,7 +135,7 @@ export default defineComponent({ let videos = [] let name, thumbnailUrl - if (!process.env.IS_ELECTRON || this.backendPreference === 'invidious') { + if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious') { if (useRss) { ({ videos, name, thumbnailUrl } = await this.getChannelVideosInvidiousRSS(channel)) } else { @@ -312,7 +312,7 @@ export default defineComponent({ resolve(this.getChannelVideosInvidiousRSS(channel, failedAttempts + 1)) break case 1: - if (process.env.IS_ELECTRON && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendFallback) { showToast(this.$t('Falling back to Local API')) resolve(this.getChannelVideosLocalScraper(channel, failedAttempts + 1)) } else { @@ -358,7 +358,7 @@ export default defineComponent({ case 0: return this.getChannelVideosInvidiousScraper(channel, failedAttempts + 1) case 1: - if (process.env.IS_ELECTRON && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendFallback) { showToast(this.$t('Falling back to Local API')) return this.getChannelVideosLocalRSS(channel, failedAttempts + 1) } else { diff --git a/src/renderer/components/theme-settings/theme-settings.js b/src/renderer/components/theme-settings/theme-settings.js index e3e9c95f7..d53bf2f92 100644 --- a/src/renderer/components/theme-settings/theme-settings.js +++ b/src/renderer/components/theme-settings/theme-settings.js @@ -6,7 +6,7 @@ import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue' import FtSlider from '../ft-slider/ft-slider.vue' import FtFlexBox from '../ft-flex-box/ft-flex-box.vue' import FtPrompt from '../ft-prompt/ft-prompt.vue' -import { colors } from '../../helpers/colors' +import { colors, getColorTranslations } from '../../helpers/colors' export default defineComponent({ name: 'ThemeSettings', @@ -20,6 +20,7 @@ export default defineComponent({ }, data: function () { return { + usingElectron: process.env.IS_ELECTRON, minUiScale: 50, maxUiScale: 300, uiScaleStep: 5, @@ -113,19 +114,11 @@ export default defineComponent({ }, colorNames: function () { - return this.colorValues.map(colorVal => { - // add spaces before capital letters - const colorName = colorVal.replaceAll(/([A-Z])/g, ' $1').trim() - return this.$t(`Settings.Theme Settings.Main Color Theme.${colorName}`) - }) + return getColorTranslations() }, areColorThemesEnabled: function() { return this.baseTheme !== 'hotPink' - }, - - usingElectron: function () { - return process.env.IS_ELECTRON } }, mounted: function () { diff --git a/src/renderer/components/top-nav/top-nav.js b/src/renderer/components/top-nav/top-nav.js index 785f869bf..eb6fa550c 100644 --- a/src/renderer/components/top-nav/top-nav.js +++ b/src/renderer/components/top-nav/top-nav.js @@ -8,6 +8,7 @@ import debounce from 'lodash.debounce' import { IpcChannels } from '../../../constants' import { openInternalPath } from '../../helpers/utils' +import { translateWindowTitle } from '../../helpers/strings' import { clearLocalSearchSuggestionsSession, getLocalSearchSuggestions } from '../../helpers/api/local' import { invidiousAPICall } from '../../helpers/api/invidious' @@ -48,9 +49,10 @@ export default defineComponent({ headerLogoTitle: function () { return this.$t('Go to page', { - page: this.$t(this.$router.getRoutes() + page: translateWindowTitle(this.$router.getRoutes() .find((route) => route.path === '/' + this.landingPage) - .meta.title + .meta.title, + this.$i18n ) }) }, @@ -288,7 +290,7 @@ export default defineComponent({ this.searchSuggestionsDataList = results.suggestions }).catch((err) => { console.error(err) - if (process.env.IS_ELECTRON && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendFallback) { console.error( 'Error gettings search suggestions. Falling back to Local API' ) diff --git a/src/renderer/components/watch-video-chapters/watch-video-chapters.js b/src/renderer/components/watch-video-chapters/watch-video-chapters.js index 9c4848893..74885cbdf 100644 --- a/src/renderer/components/watch-video-chapters/watch-video-chapters.js +++ b/src/renderer/components/watch-video-chapters/watch-video-chapters.js @@ -33,7 +33,27 @@ export default defineComponent({ compact: function () { return !this.chapters[0].thumbnail - } + }, + + observeVisibilityOptions() { + return { + callback: (isVisible, _entry) => { + // This is also fired when **hidden** + // No point doing anything if not visible + if (!isVisible) { return } + // Only auto scroll when expanded + if (!this.showChapters) { return } + + this.scrollToCurrentChapter() + }, + intersection: { + // Only when it intersects with N% above bottom + rootMargin: '0% 0% 0% 0%', + }, + // Callback responsible for scolling to current chapter multiple times + once: false, + } + }, }, watch: { currentChapterIndex: function (value) { diff --git a/src/renderer/components/watch-video-chapters/watch-video-chapters.vue b/src/renderer/components/watch-video-chapters/watch-video-chapters.vue index be6c25a06..172eecd54 100644 --- a/src/renderer/components/watch-video-chapters/watch-video-chapters.vue +++ b/src/renderer/components/watch-video-chapters/watch-video-chapters.vue @@ -28,6 +28,7 @@
{ copyToClipboard(err) }) - if (process.env.IS_ELECTRON && this.backendFallback && this.backendPreference === 'invidious') { + if (process.env.SUPPORTS_LOCAL_API && this.backendFallback && this.backendPreference === 'invidious') { showToast(this.$t('Falling back to Local API')) this.getCommentDataLocal() } else { diff --git a/src/renderer/components/watch-video-info/watch-video-info.vue b/src/renderer/components/watch-video-info/watch-video-info.vue index 76843dbb4..f5d36af02 100644 --- a/src/renderer/components/watch-video-info/watch-video-info.vue +++ b/src/renderer/components/watch-video-info/watch-video-info.vue @@ -90,7 +90,7 @@ { copyToClipboard(err) }) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { showToast(this.$t('Falling back to Local API')) this.getPlaylistInformationLocal() } else { diff --git a/src/renderer/helpers/api/invidious.js b/src/renderer/helpers/api/invidious.js index b50c54ef4..2d5c9b726 100644 --- a/src/renderer/helpers/api/invidious.js +++ b/src/renderer/helpers/api/invidious.js @@ -321,10 +321,10 @@ export function filterInvidiousFormats(formats, allowAv1 = false) { // Which is caused by Invidious API limitation on AV1 formats (see related issues) // Commented code to be restored after Invidious issue fixed // - // As we generate our own DASH manifest (using YouTube.js) for multiple audio track support in Electron, - // we can allow AV1 in that situation. If we aren't in electron, + // As we generate our own DASH manifest (using YouTube.js) for multiple audio track support when the local API is supported, + // we can allow AV1 in that situation. When the local API isn't supported, // we still can't use them until Invidious fixes the issue on their side - if (process.env.IS_ELECTRON && allowAv1 && av1Formats.length > 0) { + if (process.env.SUPPORTS_LOCAL_API && allowAv1 && av1Formats.length > 0) { return [...audioFormats, ...av1Formats] } diff --git a/src/renderer/helpers/api/local.js b/src/renderer/helpers/api/local.js index 5d14ba5bd..7b9947441 100644 --- a/src/renderer/helpers/api/local.js +++ b/src/renderer/helpers/api/local.js @@ -1,4 +1,4 @@ -import { ClientType, Endpoints, Innertube, Misc, Utils, YT } from 'youtubei.js' +import { ClientType, Endpoints, Innertube, Misc, UniversalCache, Utils, YT } from 'youtubei.js' import Autolinker from 'autolinker' import { join } from 'path' @@ -39,8 +39,12 @@ const TRACKING_PARAM_NAMES = [ async function createInnertube({ withPlayer = false, location = undefined, safetyMode = false, clientType = undefined, generateSessionLocally = true } = {}) { let cache if (withPlayer) { - const userData = await getUserDataPath() - cache = new PlayerCache(join(userData, 'player_cache')) + if (process.env.IS_ELECTRON) { + const userData = await getUserDataPath() + cache = new PlayerCache(join(userData, 'player_cache')) + } else { + cache = new UniversalCache(false) + } } return await Innertube.create({ @@ -77,8 +81,8 @@ export async function getLocalPlaylist(id) { } /** - * @param {Playlist} playlist - * @returns {Playlist|null} null when no valid playlist can be found (e.g. `empty continuation response`) + * @param {import('youtubei.js').YT.Playlist} playlist + * @returns {import('youtubei.js').YT.Playlist|null} null when no valid playlist can be found (e.g. `empty continuation response`) */ export async function getLocalPlaylistContinuation(playlist) { try { @@ -98,11 +102,11 @@ export async function getLocalPlaylistContinuation(playlist) { * Callback for adding two numbers. * * @callback untilEndOfLocalPlayListCallback - * @param {Playlist} playlist + * @param {import('youtubei.js').YT.Playlist} playlist */ /** - * @param {Playlist} playlist + * @param {import('youtubei.js').YT.Playlist} playlist * @param {untilEndOfLocalPlayListCallback} callback * @param {object} options * @param {boolean} options.runCallbackOnceFirst @@ -331,7 +335,7 @@ export async function getLocalChannelLiveStreams(id) { // it has some empty fields in the protobuf but it doesn't work if you remove them) })) - const liveStreamsTab = new YT.Channel(null, response) + let liveStreamsTab = new YT.Channel(innertube.actions, response) const { id: channelId = id, name, thumbnailUrl } = parseLocalChannelHeader(liveStreamsTab) let videos @@ -339,7 +343,16 @@ export async function getLocalChannelLiveStreams(id) { // if the channel doesn't have a live tab, YouTube returns the home tab instead // so we need to check that we got the right tab if (liveStreamsTab.current_tab?.endpoint.metadata.url?.endsWith('/streams')) { - videos = parseLocalChannelVideos(liveStreamsTab.videos, channelId, name) + // work around YouTube bug where it will return a bunch of responses with only continuations in them + // e.g. https://www.youtube.com/@TWLIVES/streams + + let tempVideos = liveStreamsTab.videos + while (tempVideos.length === 0 && liveStreamsTab.has_continuation) { + liveStreamsTab = await liveStreamsTab.getContinuation() + tempVideos = liveStreamsTab.videos + } + + videos = parseLocalChannelVideos(tempVideos, channelId, name) } else { videos = [] } @@ -513,7 +526,13 @@ export function parseLocalChannelHeader(channel) { } if (header.content.metadata) { - subscriberText = header.content.metadata.metadata_rows[0].metadata_parts[1].text.text + // YouTube has already changed the indexes for where the information is stored once, + // so we should search for it instead of using hardcoded indexes, just to be safe for the future + + subscriberText = header.content.metadata.metadata_rows + .flatMap(row => row.metadata_parts ? row.metadata_parts : []) + .find(part => part.text.text?.includes('subscriber')) + ?.text.text } break @@ -567,51 +586,66 @@ export function parseLocalChannelShorts(shorts, channelId, channelName) { } /** - * @typedef {import('youtubei.js').YTNodes.Playlist} Playlist - * @typedef {import('youtubei.js').YTNodes.GridPlaylist} GridPlaylist - */ - -/** - * @param {Playlist|GridPlaylist} playlist + * @param {import('youtubei.js').YTNodes.Playlist|import('youtubei.js').YTNodes.GridPlaylist|import('youtubei.js').YTNodes.LockupView} playlist * @param {string} channelId * @param {string} chanelName */ export function parseLocalListPlaylist(playlist, channelId = undefined, channelName = undefined) { - let internalChannelName - let internalChannelId = null + if (playlist.type === 'LockupView') { + /** @type {import('youtubei.js').YTNodes.LockupView} */ + const lockupView = playlist - if (playlist.author && playlist.author.id !== 'N/A') { - if (playlist.author instanceof Misc.Text) { - internalChannelName = playlist.author.text + /** @type {import('youtubei.js').YTNodes.ThumbnailOverlayBadgeView} */ + const thumbnailOverlayBadgeView = lockupView.content_image.primary_thumbnail.overlays + .find(overlay => overlay.type === 'ThumbnailOverlayBadgeView') - if (channelId) { - internalChannelId = channelId - } - } else { - internalChannelName = playlist.author.name - internalChannelId = playlist.author.id + return { + type: 'playlist', + dataSource: 'local', + title: lockupView.metadata.title.text, + thumbnail: lockupView.content_image.primary_thumbnail.image[0].url, + channelName, + channelId, + playlistId: lockupView.content_id, + videoCount: extractNumberFromString(thumbnailOverlayBadgeView.badges[0].text) } - } else if (channelId || channelName) { - internalChannelName = channelName - internalChannelId = channelId - } else if (playlist.author?.name) { - // auto-generated album playlists don't have an author - // so in search results, the author text is "Playlist" and doesn't have a link or channel ID - internalChannelName = playlist.author.name - } + } else { + let internalChannelName + let internalChannelId = null - /** @type {import('youtubei.js').YTNodes.PlaylistVideoThumbnail} */ - const thumbnailRenderer = playlist.thumbnail_renderer + if (playlist.author && playlist.author.id !== 'N/A') { + if (playlist.author instanceof Misc.Text) { + internalChannelName = playlist.author.text - return { - type: 'playlist', - dataSource: 'local', - title: playlist.title.text, - thumbnail: thumbnailRenderer ? thumbnailRenderer.thumbnail[0].url : playlist.thumbnails[0].url, - channelName: internalChannelName, - channelId: internalChannelId, - playlistId: playlist.id, - videoCount: extractNumberFromString(playlist.video_count.text) + if (channelId) { + internalChannelId = channelId + } + } else { + internalChannelName = playlist.author.name + internalChannelId = playlist.author.id + } + } else if (channelId || channelName) { + internalChannelName = channelName + internalChannelId = channelId + } else if (playlist.author?.name) { + // auto-generated album playlists don't have an author + // so in search results, the author text is "Playlist" and doesn't have a link or channel ID + internalChannelName = playlist.author.name + } + + /** @type {import('youtubei.js').YTNodes.PlaylistVideoThumbnail} */ + const thumbnailRenderer = playlist.thumbnail_renderer + + return { + type: 'playlist', + dataSource: 'local', + title: playlist.title.text, + thumbnail: thumbnailRenderer ? thumbnailRenderer.thumbnail[0].url : playlist.thumbnails[0].url, + channelName: internalChannelName, + channelId: internalChannelId, + playlistId: playlist.id, + videoCount: extractNumberFromString(playlist.video_count.text) + } } } @@ -738,7 +772,7 @@ export function parseLocalListVideo(item) { let publishedText - if (!video.published?.isEmpty()) { + if (video.published != null && !video.published.isEmpty()) { publishedText = video.published.text } @@ -834,7 +868,7 @@ function parseListItem(item) { export function parseLocalWatchNextVideo(video) { let publishedText - if (!video.published?.isEmpty()) { + if (video.published != null && !video.published.isEmpty()) { publishedText = video.published.text } @@ -1023,7 +1057,7 @@ export function mapLocalFormat(format) { } /** - * @param {import('youtubei.js').YTNodes.Comment} comment + * @param {import('youtubei.js').YTNodes.Comment|import('youtubei.js').YTNodes.CommentView} comment * @param {import('youtubei.js').YTNodes.CommentThread} commentThread */ export function parseLocalComment(comment, commentThread = undefined) { @@ -1035,26 +1069,48 @@ export function parseLocalComment(comment, commentThread = undefined) { replyToken = commentThread } - return { + const parsed = { dataType: 'local', authorLink: comment.author.id, author: comment.author.name, authorId: comment.author.id, authorThumb: comment.author.best_thumbnail.url, isPinned: comment.is_pinned, - isOwner: comment.author_is_channel_owner, - isMember: comment.is_member, - memberIconUrl: comment.is_member ? comment.sponsor_comment_badge.custom_badge[0].url : '', + isOwner: !!comment.author_is_channel_owner, + isMember: !!comment.is_member, text: Autolinker.link(parseLocalTextRuns(comment.content.runs, 16, { looseChannelNameDetection: true })), - time: toLocalePublicationString({ publishText: comment.published.text.replace('(edited)', '').trim() }), - likes: comment.vote_count, - isHearted: comment.is_hearted, - numReplies: comment.reply_count, + isHearted: !!comment.is_hearted, hasOwnerReplied, replyToken, showReplies: false, - replies: [] + replies: [], + + // default values for the properties set below + memberIconUrl: '', + time: '', + likes: 0, + numReplies: 0 } + + if (comment.type === 'Comment') { + /** @type {import('youtubei.js').YTNodes.Comment} */ + const comment_ = comment + + parsed.memberIconUrl = comment_.is_member ? comment_.sponsor_comment_badge.custom_badge[0].url : '' + parsed.time = toLocalePublicationString({ publishText: comment_.published.text.replace('(edited)', '').trim() }) + parsed.likes = comment_.vote_count + parsed.numReplies = comment_.reply_count + } else { + /** @type {import('youtubei.js').YTNodes.CommentView} */ + const commentView = comment + + parsed.memberIconUrl = commentView.is_member ? commentView.member_badge.url : '' + parsed.time = toLocalePublicationString({ publishText: commentView.published_time.replace('(edited)', '').trim() }) + parsed.likes = commentView.like_count + parsed.numReplies = parseLocalSubscriberCount(commentView.reply_count) + } + + return parsed } /** @@ -1088,32 +1144,40 @@ export function filterLocalFormats(formats, allowAv1 = false) { } /** - * Really not a fan of this :(, YouTube returns the subscribers as "15.1M subscribers" - * so we have to parse it somehow * @param {string} text */ export function parseLocalSubscriberCount(text) { - const match = text - .replace(',', '.') - .toUpperCase() - .match(/([\d.]+)\s*([KM]?)/) + const match = text.match(/(\d+)(?:[,.](\d+))?\s?([BKMbkm])\b/) - let subscribers if (match) { - subscribers = parseFloat(match[1]) + let multiplier = 0 - if (match[2] === 'K') { - subscribers *= 1000 - } else if (match[2] === 'M') { - subscribers *= 1000_000 + switch (match[3]) { + case 'K': + case 'k': + multiplier = 3 + break + case 'M': + case 'm': + multiplier = 6 + break + case 'B': + case 'b': + multiplier = 9 + break } - subscribers = Math.trunc(subscribers) - } else { - subscribers = extractNumberFromString(text) - } + let parsedDecimals + if (typeof match[2] === 'undefined') { + parsedDecimals = '0'.repeat(multiplier) + } else { + parsedDecimals = match[2].padEnd(multiplier, '0') + } - return subscribers + return parseInt(match[1] + parsedDecimals) + } else { + return extractNumberFromString(text) + } } /** diff --git a/src/renderer/helpers/channels.js b/src/renderer/helpers/channels.js index 888c13178..e343bdbac 100644 --- a/src/renderer/helpers/channels.js +++ b/src/renderer/helpers/channels.js @@ -11,7 +11,7 @@ import { getLocalChannel } from './api/local' */ async function findChannelById(id, backendOptions) { try { - if (!process.env.IS_ELECTRON || backendOptions.preference === 'invidious') { + if (!process.env.SUPPORTS_LOCAL_API || backendOptions.preference === 'invidious') { return await invidiousGetChannelInfo(id) } else { return await getLocalChannel(id) @@ -21,7 +21,7 @@ async function findChannelById(id, backendOptions) { if (err.message && err.message === 'This channel does not exist.') { return { invalid: true } } - if (process.env.IS_ELECTRON && backendOptions.fallback) { + if (process.env.SUPPORTS_LOCAL_API && backendOptions.fallback) { if (backendOptions.preference === 'invidious') { return await getLocalChannel(id) } @@ -46,7 +46,7 @@ export async function findChannelTagInfo(id, backendOptions) { if (!checkYoutubeChannelId(id)) return { invalidId: true } try { const channel = await findChannelById(id, backendOptions) - if (!process.env.IS_ELECTRON || backendOptions.preference === 'invidious') { + if (!process.env.SUPPORTS_LOCAL_API || backendOptions.preference === 'invidious') { if (channel.invalid) return { invalidId: true } return { preferredName: channel.author, diff --git a/src/renderer/helpers/colors.js b/src/renderer/helpers/colors.js index e09fbdd86..eb58004a0 100644 --- a/src/renderer/helpers/colors.js +++ b/src/renderer/helpers/colors.js @@ -1,3 +1,5 @@ +import i18n from '../i18n/index' + export const colors = [ { name: 'Red', value: '#d50000' }, { name: 'Pink', value: '#C51162' }, @@ -38,14 +40,55 @@ export const colors = [ { name: 'CatppuccinMochaLavender', value: '#B4BEFE' } ] +export function getColorTranslations() { + return [ + i18n.t('Settings.Theme Settings.Main Color Theme.Red'), + i18n.t('Settings.Theme Settings.Main Color Theme.Pink'), + i18n.t('Settings.Theme Settings.Main Color Theme.Purple'), + i18n.t('Settings.Theme Settings.Main Color Theme.Deep Purple'), + i18n.t('Settings.Theme Settings.Main Color Theme.Indigo'), + i18n.t('Settings.Theme Settings.Main Color Theme.Blue'), + i18n.t('Settings.Theme Settings.Main Color Theme.Light Blue'), + i18n.t('Settings.Theme Settings.Main Color Theme.Cyan'), + i18n.t('Settings.Theme Settings.Main Color Theme.Teal'), + i18n.t('Settings.Theme Settings.Main Color Theme.Green'), + i18n.t('Settings.Theme Settings.Main Color Theme.Light Green'), + i18n.t('Settings.Theme Settings.Main Color Theme.Lime'), + i18n.t('Settings.Theme Settings.Main Color Theme.Yellow'), + i18n.t('Settings.Theme Settings.Main Color Theme.Amber'), + i18n.t('Settings.Theme Settings.Main Color Theme.Orange'), + i18n.t('Settings.Theme Settings.Main Color Theme.Deep Orange'), + i18n.t('Settings.Theme Settings.Main Color Theme.Dracula Cyan'), + i18n.t('Settings.Theme Settings.Main Color Theme.Dracula Green'), + i18n.t('Settings.Theme Settings.Main Color Theme.Dracula Orange'), + i18n.t('Settings.Theme Settings.Main Color Theme.Dracula Pink'), + i18n.t('Settings.Theme Settings.Main Color Theme.Dracula Purple'), + i18n.t('Settings.Theme Settings.Main Color Theme.Dracula Red'), + i18n.t('Settings.Theme Settings.Main Color Theme.Dracula Yellow'), + i18n.t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Rosewater'), + i18n.t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Flamingo'), + i18n.t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Pink'), + i18n.t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Mauve'), + i18n.t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Red'), + i18n.t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Maroon'), + i18n.t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Peach'), + i18n.t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Yellow'), + i18n.t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Green'), + i18n.t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Teal'), + i18n.t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Sky'), + i18n.t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Sapphire'), + i18n.t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Blue'), + i18n.t('Settings.Theme Settings.Main Color Theme.Catppuccin Mocha Lavender') + ] +} + export function getRandomColorClass() { - const randomInt = Math.floor(Math.random() * colors.length) - return 'main' + colors[randomInt].name + return 'main' + getRandomColor().name } export function getRandomColor() { const randomInt = Math.floor(Math.random() * colors.length) - return colors[randomInt].value + return colors[randomInt] } export function calculateColorLuminance(colorValue) { diff --git a/src/renderer/helpers/strings.js b/src/renderer/helpers/strings.js index f83a0ea11..255630484 100644 --- a/src/renderer/helpers/strings.js +++ b/src/renderer/helpers/strings.js @@ -23,3 +23,32 @@ export function isKeyboardEventKeyPrintableChar(eventKey) { return false } + +export function translateWindowTitle(title, i18n) { + switch (title) { + case 'Subscriptions': + return i18n.t('Subscriptions.Subscriptions') + case 'Channels': + return i18n.t('Channels.Title') + case 'Trending': + return i18n.t('Trending.Trending') + case 'Most Popular': + return i18n.t('Most Popular') + case 'Your Playlists': + return i18n.t('User Playlists.Your Playlists') + case 'History': + return i18n.t('History.History') + case 'Settings': + return i18n.t('Settings.Settings') + case 'About': + return i18n.t('About.About') + case 'Profile Settings': + return i18n.t('Profile.Profile Settings') + case 'Search Results': + return i18n.t('Search Filters.Search Results') + case 'Playlist': + return i18n.t('Playlist.Playlist') + default: + return null + } +} diff --git a/src/renderer/helpers/utils.js b/src/renderer/helpers/utils.js index fd3016062..1a0850e07 100644 --- a/src/renderer/helpers/utils.js +++ b/src/renderer/helpers/utils.js @@ -92,43 +92,67 @@ export function toLocalePublicationString ({ publishText, isLive = false, isUpco const match = publishText.match(PUBLISHED_TEXT_REGEX) const singular = (match[1] === '1') - let translationKey = '' + let unit = '' switch (match[2].substring(0, 2)) { case 'se': case 's': - translationKey = 'Video.Published.Second' + if (singular) { + unit = i18n.t('Video.Published.Second') + } else { + unit = i18n.t('Video.Published.Seconds') + } break case 'mi': case 'm': - translationKey = 'Video.Published.Minute' + if (singular) { + unit = i18n.t('Video.Published.Minute') + } else { + unit = i18n.t('Video.Published.Minutes') + } break case 'ho': case 'h': - translationKey = 'Video.Published.Hour' + if (singular) { + unit = i18n.t('Video.Published.Hour') + } else { + unit = i18n.t('Video.Published.Hours') + } break case 'da': case 'd': - translationKey = 'Video.Published.Day' + if (singular) { + unit = i18n.t('Video.Published.Day') + } else { + unit = i18n.t('Video.Published.Days') + } break case 'we': case 'w': - translationKey = 'Video.Published.Week' + if (singular) { + unit = i18n.t('Video.Published.Week') + } else { + unit = i18n.t('Video.Published.Weeks') + } break case 'mo': - translationKey = 'Video.Published.Month' + if (singular) { + unit = i18n.t('Video.Published.Month') + } else { + unit = i18n.t('Video.Published.Months') + } break case 'ye': case 'y': - translationKey = 'Video.Published.Year' + if (singular) { + unit = i18n.t('Video.Published.Year') + } else { + unit = i18n.t('Video.Published.Years') + } break default: return publishText } - if (!singular) { - translationKey += 's' - } - const unit = i18n.t(translationKey) return i18n.t('Video.Publicationtemplate', { number: match[1], unit }) } @@ -574,8 +598,7 @@ export function extractNumberFromString(str) { } } -export function showExternalPlayerUnsupportedActionToast(externalPlayer, actionName) { - const action = i18n.t(`Video.External Player.Unsupported Actions.${actionName}`) +export function showExternalPlayerUnsupportedActionToast(externalPlayer, action) { const message = i18n.t('Video.External Player.UnsupportedActionTemplate', { externalPlayer, action }) showToast(message) } diff --git a/src/renderer/i18n/index.js b/src/renderer/i18n/index.js index a91568be6..454c439aa 100644 --- a/src/renderer/i18n/index.js +++ b/src/renderer/i18n/index.js @@ -8,7 +8,20 @@ Vue.use(VueI18n) const i18n = new VueI18n({ locale: 'en-US', - fallbackLocale: { default: 'en-US' } + fallbackLocale: { + // https://kazupon.github.io/vue-i18n/guide/fallback.html#explicit-fallback-with-decision-maps + + // es_AR -> es -> en-US + es_AR: ['es'], + // es-MX -> es -> en-US + 'es-MX': ['es'], + // pt-BR -> pt -> en-US + 'pt-BR': ['pt'], + // pt-PT -> pt -> en-US + 'pt-PT': ['pt'], + // any -> en-US + default: ['en-US'], + } }) export async function loadLocale(locale) { @@ -18,6 +31,7 @@ export async function loadLocale(locale) { } if (!activeLocales.includes(locale)) { console.error(`Unable to load unknown locale: "${locale}"`) + return } // locales are only compressed in our production Electron builds @@ -45,6 +59,4 @@ export async function loadLocale(locale) { } } -loadLocale('en-US') - export default i18n diff --git a/src/renderer/main.js b/src/renderer/main.js index 6a5cd9136..11d878908 100644 --- a/src/renderer/main.js +++ b/src/renderer/main.js @@ -63,7 +63,6 @@ import { faShareAlt, faSlidersH, faSortDown, - faStar, faStepBackward, faStepForward, faSync, @@ -143,7 +142,6 @@ library.add( faShareAlt, faSlidersH, faSortDown, - faStar, faStepBackward, faStepForward, faSync, diff --git a/src/renderer/router/index.js b/src/renderer/router/index.js index bce2ce775..2185a7d48 100644 --- a/src/renderer/router/index.js +++ b/src/renderer/router/index.js @@ -23,7 +23,7 @@ const router = new Router({ path: '/', name: 'default', meta: { - title: 'Subscriptions.Subscriptions' + title: 'Subscriptions' }, component: Subscriptions }, @@ -31,7 +31,7 @@ const router = new Router({ path: '/subscriptions', name: 'subscriptions', meta: { - title: 'Subscriptions.Subscriptions' + title: 'Subscriptions' }, component: Subscriptions }, @@ -39,7 +39,7 @@ const router = new Router({ path: '/subscribedchannels', name: 'subscribedChannels', meta: { - title: 'Channels.Title' + title: 'Channels' }, component: SubscribedChannels }, @@ -47,7 +47,7 @@ const router = new Router({ path: '/trending', name: 'trending', meta: { - title: 'Trending.Trending' + title: 'Trending' }, component: Trending }, @@ -63,7 +63,7 @@ const router = new Router({ path: '/userplaylists', name: 'userPlaylists', meta: { - title: 'User Playlists.Your Playlists' + title: 'Your Playlists' }, component: UserPlaylists }, @@ -71,7 +71,7 @@ const router = new Router({ path: '/history', name: 'history', meta: { - title: 'History.History' + title: 'History' }, component: History }, @@ -79,7 +79,7 @@ const router = new Router({ path: '/settings', name: 'settings', meta: { - title: 'Settings.Settings' + title: 'Settings' }, component: Settings }, @@ -87,7 +87,7 @@ const router = new Router({ path: '/about', name: 'about', meta: { - title: 'About.About' + title: 'About' }, component: About }, @@ -95,21 +95,21 @@ const router = new Router({ path: '/settings/profile', name: 'profileSettings', meta: { - title: 'Profile.Profile Settings' + title: 'Profile Settings' }, component: ProfileSettings }, { path: '/search/:query', meta: { - title: 'Search Filters.Search Results' + title: 'Search Results' }, component: Search }, { path: '/playlist/:id', meta: { - title: 'Playlist.Playlist' + title: 'Playlist' }, component: Playlist }, diff --git a/src/renderer/scss-partials/_ft-list-item.scss b/src/renderer/scss-partials/_ft-list-item.scss index 624d21093..22be37765 100644 --- a/src/renderer/scss-partials/_ft-list-item.scss +++ b/src/renderer/scss-partials/_ft-list-item.scss @@ -366,7 +366,7 @@ $watched-transition-duration: 0.5s; &:has(:focus-visible) .addToPlaylistIcon:not(.alwaysVisible), &:has(:focus-visible) .quickBookmarkVideoIcon:not(.alwaysVisible), &:has(:focus-visible) .externalPlayerIcon { - opacity: $thumbnail-overlay-opacity; + opacity: 1; } &:hover .optionsButton, @@ -386,45 +386,6 @@ $watched-transition-duration: 0.5s; } } -.ft-list-channel { - .infoAndSubscribe { - display: flex; - flex-flow: row wrap; - justify-content: center; - inline-size: 100%; - } - - &.grid { - align-items: center; - text-align: center; - - .infoAndSubscribe { - flex-flow: column wrap; - align-items: center; - - .info { - margin-block-end: 12px; - - .infoLine { - text-align: center; - } - } - } - } - - &.list { - .infoAndSubscribe { - flex-flow: row wrap; - justify-content: center; - - .channelSubscribeButton { - margin-block: auto; - margin-inline: 7px; - } - } - } -} - .videoWatched, .live, .upcoming { diff --git a/src/renderer/store/modules/invidious.js b/src/renderer/store/modules/invidious.js index b7b9aa414..90cdc1f90 100644 --- a/src/renderer/store/modules/invidious.js +++ b/src/renderer/store/modules/invidious.js @@ -28,7 +28,7 @@ const actions = { return !(instance[0].includes('.onion') || instance[0].includes('.i2p') || !instance[1].api || - (!process.env.IS_ELECTRON && !instance[1].cors)) + (!process.env.SUPPORTS_LOCAL_API && !instance[1].cors)) }).map((instance) => { return instance[1].uri.replace(/\/$/, '') }) @@ -50,7 +50,7 @@ const actions = { console.warn('reading static file for invidious instances') const fileData = process.env.IS_ELECTRON ? await fs.readFile(filePath, 'utf8') : await (await fetch(createWebURL(filePath))).text() instances = JSON.parse(fileData).filter(e => { - return process.env.IS_ELECTRON || e.cors + return process.env.SUPPORTS_LOCAL_API || e.cors }).map(e => { return e.url }) diff --git a/src/renderer/store/modules/profiles.js b/src/renderer/store/modules/profiles.js index 02630feff..34574b4df 100644 --- a/src/renderer/store/modules/profiles.js +++ b/src/renderer/store/modules/profiles.js @@ -54,7 +54,7 @@ const actions = { if (profiles.length === 0) { // Create a default profile and persist it - const randomColor = getRandomColor() + const randomColor = getRandomColor().value const textColor = calculateColorLuminance(randomColor) const defaultProfile = { _id: MAIN_PROFILE_ID, diff --git a/src/renderer/store/modules/settings.js b/src/renderer/store/modules/settings.js index e510dbea0..7aa40616c 100644 --- a/src/renderer/store/modules/settings.js +++ b/src/renderer/store/modules/settings.js @@ -165,8 +165,8 @@ const state = { allSettingsSectionsExpandedByDefault: false, autoplayPlaylists: true, autoplayVideos: true, - backendFallback: process.env.IS_ELECTRON, - backendPreference: !process.env.IS_ELECTRON ? 'invidious' : 'local', + backendFallback: process.env.SUPPORTS_LOCAL_API, + backendPreference: !process.env.SUPPORTS_LOCAL_API ? 'invidious' : 'local', barColor: false, checkForBlogPosts: true, checkForUpdates: true, @@ -237,10 +237,9 @@ const state = { proxyHostname: '127.0.0.1', proxyPort: '9050', proxyProtocol: 'socks5', - proxyVideos: !process.env.IS_ELECTRON, + proxyVideos: !process.env.SUPPORTS_LOCAL_API, region: 'US', rememberHistory: true, - removeVideoMetaFiles: true, saveWatchedProgress: true, saveVideoHistoryWithLastViewedPlaylist: true, showFamilyFriendlyOnly: false, @@ -353,7 +352,34 @@ const stateWithSideEffects = { } } - await loadLocale(targetLocale) + const loadPromises = [] + + if (targetLocale !== defaultLocale) { + // "en-US" is used as a fallback for missing strings in other locales + loadPromises.push( + loadLocale(defaultLocale) + ) + } + + // "es" is used as a fallback for "es_AR" and "es-MX" + if (targetLocale === 'es_AR' || targetLocale === 'es-MX') { + loadPromises.push( + loadLocale('es') + ) + } + + // "pt" is used as a fallback for "pt-PT" and "pt-BR" + if (targetLocale === 'pt-PT' || targetLocale === 'pt-BR') { + loadPromises.push( + loadLocale('pt') + ) + } + + loadPromises.push( + loadLocale(targetLocale) + ) + + await Promise.allSettled(loadPromises) i18n.locale = targetLocale await dispatch('getRegionData', { diff --git a/src/renderer/store/modules/subscriptions.js b/src/renderer/store/modules/subscriptions.js index c85168423..2ce05c7b6 100644 --- a/src/renderer/store/modules/subscriptions.js +++ b/src/renderer/store/modules/subscriptions.js @@ -1,9 +1,3 @@ -import { deepCopy } from '../../helpers/utils' - -const defaultCacheEntryValueForForOneChannel = { - videos: null, -} - const state = { videoCache: {}, liveCache: {}, @@ -77,7 +71,7 @@ const actions = { const mutations = { updateVideoCacheByChannel(state, { channelId, videos }) { const existingObject = state.videoCache[channelId] - const newObject = existingObject != null ? existingObject : deepCopy(defaultCacheEntryValueForForOneChannel) + const newObject = existingObject ?? { videos: null } if (videos != null) { newObject.videos = videos } state.videoCache[channelId] = newObject }, @@ -86,7 +80,7 @@ const mutations = { }, updateShortsCacheByChannel(state, { channelId, videos }) { const existingObject = state.shortsCache[channelId] - const newObject = existingObject != null ? existingObject : deepCopy(defaultCacheEntryValueForForOneChannel) + const newObject = existingObject ?? { videos: null } if (videos != null) { newObject.videos = videos } state.shortsCache[channelId] = newObject }, @@ -120,7 +114,7 @@ const mutations = { }, updateLiveCacheByChannel(state, { channelId, videos }) { const existingObject = state.liveCache[channelId] - const newObject = existingObject != null ? existingObject : deepCopy(defaultCacheEntryValueForForOneChannel) + const newObject = existingObject ?? { videos: null } if (videos != null) { newObject.videos = videos } state.liveCache[channelId] = newObject }, @@ -129,7 +123,7 @@ const mutations = { }, updatePostsCacheByChannel(state, { channelId, posts }) { const existingObject = state.postsCache[channelId] - const newObject = existingObject != null ? existingObject : deepCopy(defaultCacheEntryValueForForOneChannel) + const newObject = existingObject ?? { posts: null } if (posts != null) { newObject.posts = posts } state.postsCache[channelId] = newObject }, diff --git a/src/renderer/store/modules/utils.js b/src/renderer/store/modules/utils.js index 243520044..0a52ca7c4 100644 --- a/src/renderer/store/modules/utils.js +++ b/src/renderer/store/modules/utils.js @@ -47,7 +47,6 @@ const state = { duration: '' }, externalPlayerNames: [], - externalPlayerNameTranslationKeys: [], externalPlayerValues: [], externalPlayerCmdArguments: {} } @@ -133,10 +132,6 @@ const getters = { return state.externalPlayerNames }, - getExternalPlayerNameTranslationKeys () { - return state.externalPlayerNameTranslationKeys - }, - getExternalPlayerValues () { return state.externalPlayerValues }, @@ -262,7 +257,7 @@ const actions = { } if (parsedString !== replaceFilenameForbiddenChars(parsedString)) { - reject(new Error('Forbidden Characters')) // use message as translation key + reject(new Error(i18n.t('Settings.Player Settings.Screenshot.Error.Forbidden Characters'))) } let filename @@ -274,7 +269,7 @@ const actions = { } if (!filename) { - reject(new Error('Empty File Name')) + reject(new Error(i18n.t('Settings.Player Settings.Screenshot.Error.Empty File Name'))) } resolve(parsedString) @@ -603,7 +598,7 @@ const actions = { const fileData = await fs.readFile(`${fileLocation}${fileName}`) const externalPlayerMap = JSON.parse(fileData).map((entry) => { - return { name: entry.name, nameTranslationKey: entry.nameTranslationKey, value: entry.value, cmdArguments: entry.cmdArguments } + return { name: entry.name, value: entry.value, cmdArguments: entry.cmdArguments } }) // Sort external players alphabetically & case-insensitive, keep default entry at the top const playerNone = externalPlayerMap.shift() @@ -611,7 +606,6 @@ const actions = { externalPlayerMap.unshift(playerNone) const externalPlayerNames = externalPlayerMap.map((entry) => { return entry.name }) - const externalPlayerNameTranslationKeys = externalPlayerMap.map((entry) => { return entry.nameTranslationKey }) const externalPlayerValues = externalPlayerMap.map((entry) => { return entry.value }) const externalPlayerCmdArguments = externalPlayerMap.reduce((result, item) => { result[item.value] = item.cmdArguments @@ -619,7 +613,6 @@ const actions = { }, {}) commit('setExternalPlayerNames', externalPlayerNames) - commit('setExternalPlayerNameTranslationKeys', externalPlayerNameTranslationKeys) commit('setExternalPlayerValues', externalPlayerValues) commit('setExternalPlayerCmdArguments', externalPlayerCmdArguments) }, @@ -667,7 +660,7 @@ const actions = { args.push(cmdArgs.startOffset, Math.trunc(payload.watchProgress)) } } else if (!ignoreWarnings) { - showExternalPlayerUnsupportedActionToast(externalPlayer, 'starting video at offset') + showExternalPlayerUnsupportedActionToast(externalPlayer, i18n.t('Video.External Player.Unsupported Actions.starting video at offset')) } } @@ -675,7 +668,7 @@ const actions = { if (typeof cmdArgs.playbackRate === 'string') { args.push(`${cmdArgs.playbackRate}${payload.playbackRate}`) } else if (!ignoreWarnings) { - showExternalPlayerUnsupportedActionToast(externalPlayer, 'setting a playback rate') + showExternalPlayerUnsupportedActionToast(externalPlayer, i18n.t('Video.External Player.Unsupported Actions.setting a playback rate')) } } @@ -685,7 +678,7 @@ const actions = { if (typeof cmdArgs.playlistIndex === 'string') { args.push(`${cmdArgs.playlistIndex}${payload.playlistIndex}`) } else if (!ignoreWarnings) { - showExternalPlayerUnsupportedActionToast(externalPlayer, 'opening specific video in a playlist (falling back to opening the video)') + showExternalPlayerUnsupportedActionToast(externalPlayer, i18n.t('Video.External Player.Unsupported Actions.opening specific video in a playlist (falling back to opening the video)')) } } @@ -693,7 +686,7 @@ const actions = { if (typeof cmdArgs.playlistReverse === 'string') { args.push(cmdArgs.playlistReverse) } else if (!ignoreWarnings) { - showExternalPlayerUnsupportedActionToast(externalPlayer, 'reversing playlists') + showExternalPlayerUnsupportedActionToast(externalPlayer, i18n.t('Video.External Player.Unsupported Actions.reversing playlists')) } } @@ -701,7 +694,7 @@ const actions = { if (typeof cmdArgs.playlistShuffle === 'string') { args.push(cmdArgs.playlistShuffle) } else if (!ignoreWarnings) { - showExternalPlayerUnsupportedActionToast(externalPlayer, 'shuffling playlists') + showExternalPlayerUnsupportedActionToast(externalPlayer, i18n.t('Video.External Player.Unsupported Actions.shuffling playlists')) } } @@ -709,7 +702,7 @@ const actions = { if (typeof cmdArgs.playlistLoop === 'string') { args.push(cmdArgs.playlistLoop) } else if (!ignoreWarnings) { - showExternalPlayerUnsupportedActionToast(externalPlayer, 'looping playlists') + showExternalPlayerUnsupportedActionToast(externalPlayer, i18n.t('Video.External Player.Unsupported Actions.looping playlists')) } } @@ -721,7 +714,7 @@ const actions = { } } else { if (payload.playlistId != null && payload.playlistId !== '' && !ignoreWarnings) { - showExternalPlayerUnsupportedActionToast(externalPlayer, 'opening playlists') + showExternalPlayerUnsupportedActionToast(externalPlayer, i18n.t('Video.External Player.Unsupported Actions.opening playlists')) } if (payload.videoId != null) { args.push(`${cmdArgs.videoUrl}https://www.youtube.com/watch?v=${payload.videoId}`) @@ -874,10 +867,6 @@ const mutations = { state.externalPlayerNames = value }, - setExternalPlayerNameTranslationKeys (state, value) { - state.externalPlayerNameTranslationKeys = value - }, - setExternalPlayerValues (state, value) { state.externalPlayerValues = value }, diff --git a/src/renderer/themes.css b/src/renderer/themes.css index fd100cc5f..f5e279ae5 100644 --- a/src/renderer/themes.css +++ b/src/renderer/themes.css @@ -72,7 +72,7 @@ --primary-shadow-color: rgba(232, 232, 232, 1); --title-color: #3f7ac6; --bg-color: #f1f1f1; - --favorite-icon-color: #FFD600; + --favorite-icon-color: #00CC00; --card-bg-color: #FFFFFF; --secondary-card-bg-color: #eeeeee; --scrollbar-color: #CCCCCC; @@ -89,7 +89,7 @@ --tertiary-text-color: #999; --title-color: #EEEEEE; --bg-color: #212121; - --favorite-icon-color: #FFEA00; + --favorite-icon-color: #00FF00; --card-bg-color: #303030; --secondary-card-bg-color: rgba(0, 0, 0, 0.75); --scrollbar-color: #414141; @@ -106,7 +106,7 @@ --tertiary-text-color: #EEEEEE; --title-color: #EEEEEE; --bg-color: #000000; - --favorite-icon-color: #FFEA00; + --favorite-icon-color: #00FF00; --card-bg-color: #000000; --secondary-card-bg-color: rgba(0, 0, 0, 0.75); --scrollbar-color: #515151; @@ -137,7 +137,7 @@ --tertiary-text-color: #e5e8f3; --title-color: #BD93F9; --bg-color: #282A36; - --favorite-icon-color: #F1FA8C; + --favorite-icon-color: #00FF00; --card-bg-color: #33353F; --secondary-card-bg-color: #282A36; --scrollbar-color: #44475A; @@ -156,7 +156,7 @@ --tertiary-text-color: #a6adc8; --title-color: var(--accent-color); --bg-color: #1e1e2e; - --favorite-icon-color: #f9e2af; + --favorite-icon-color: #00FF00; --card-bg-color: #181825; --secondary-card-bg-color: #1e1e2e; --scrollbar-color: #313244; @@ -197,7 +197,7 @@ --tertiary-text-color: #FFFF; --title-color: #000000; --bg-color: #ff008a; - --favorite-icon-color: #FFEA00; + --favorite-icon-color: #00FF00; --card-bg-color: #DE1C85; --secondary-card-bg-color: rgba(0, 0, 0, 0.75); --scrollbar-color: #FFFFFF; @@ -248,7 +248,7 @@ it can be safely elided. This looks quite pleasant on this theme. */ --tertiary-text-color: #EEEEEE; --title-color: #EEEEEE; --bg-color: #2b2f3a; - --favorite-icon-color: #FFEA00; + --favorite-icon-color: #00FF00; --card-bg-color: #2e3440; --secondary-card-bg-color: rgba(59, 66, 82, 0.75); --scrollbar-color: #4b566a; diff --git a/src/renderer/views/Channel/Channel.js b/src/renderer/views/Channel/Channel.js index 7ea6c27e5..5f17b1920 100644 --- a/src/renderer/views/Channel/Channel.js +++ b/src/renderer/views/Channel/Channel.js @@ -105,15 +105,11 @@ export default defineComponent({ errorMessage: '', showSearchBar: true, showShareMenu: true, - videoLiveSelectValues: [ + videoLiveShortSelectValues: [ 'newest', 'popular', 'oldest' ], - shortSelectValues: [ - 'newest', - 'popular' - ], playlistSelectValues: [ 'newest', 'last' @@ -184,7 +180,7 @@ export default defineComponent({ return profileList[0].subscriptions.some((channel) => channel.id === this.id) }, - videoLiveSelectNames: function () { + videoLiveShortSelectNames: function () { return [ this.$t('Channel.Videos.Sort Types.Newest'), this.$t('Channel.Videos.Sort Types.Most Popular'), @@ -192,13 +188,6 @@ export default defineComponent({ ] }, - shortSelectNames: function () { - return [ - this.$t('Channel.Videos.Sort Types.Newest'), - this.$t('Channel.Videos.Sort Types.Most Popular') - ] - }, - playlistSelectNames: function () { return [ this.$t('Channel.Playlists.Sort Types.Newest'), @@ -362,7 +351,7 @@ export default defineComponent({ this.errorMessage = '' // Re-enable auto refresh on sort value change AFTER update done - if (!process.env.IS_ELECTRON || this.backendPreference === 'invidious') { + if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious') { this.getChannelInfoInvidious() this.autoRefreshOnSortByChangeEnabled = true } else { @@ -460,7 +449,7 @@ export default defineComponent({ } // Enable auto refresh on sort value change AFTER initial update done - if (!process.env.IS_ELECTRON || this.backendPreference === 'invidious') { + if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious') { this.getChannelInfoInvidious() this.autoRefreshOnSortByChangeEnabled = true } else { @@ -473,7 +462,7 @@ export default defineComponent({ resolveChannelUrl: async function (url, tab = undefined) { let id - if (!process.env.IS_ELECTRON || this.backendPreference === 'invidious') { + if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious') { id = await invidiousGetChannelId(url) } else { id = await getLocalChannelId(url) @@ -769,7 +758,7 @@ export default defineComponent({ this.showVideoSortBy = videosTab.filters.length > 1 if (this.showVideoSortBy && this.videoSortBy !== 'newest') { - const index = this.videoLiveSelectValues.indexOf(this.videoSortBy) + const index = this.videoLiveShortSelectValues.indexOf(this.videoSortBy) videosTab = await videosTab.applyFilter(videosTab.filters[index]) } @@ -837,7 +826,7 @@ export default defineComponent({ this.showShortSortBy = shortsTab.filters.length > 1 if (this.showShortSortBy && this.shortSortBy !== 'newest') { - const index = this.shortSelectValues.indexOf(this.shortSortBy) + const index = this.videoLiveShortSelectValues.indexOf(this.shortSortBy) shortsTab = await shortsTab.applyFilter(shortsTab.filters[index]) } @@ -905,7 +894,7 @@ export default defineComponent({ this.showLiveSortBy = liveTab.filters.length > 1 if (this.showLiveSortBy && this.liveSortBy !== 'newest') { - const index = this.videoLiveSelectValues.indexOf(this.liveSortBy) + const index = this.videoLiveShortSelectValues.indexOf(this.liveSortBy) liveTab = await liveTab.applyFilter(liveTab.filters[index]) } @@ -913,7 +902,16 @@ export default defineComponent({ return } - this.latestLive = parseLocalChannelVideos(liveTab.videos, this.id, this.channelName) + // work around YouTube bug where it will return a bunch of responses with only continuations in them + // e.g. https://www.youtube.com/@TWLIVES/streams + + let videos = liveTab.videos + while (videos.length === 0 && liveTab.has_continuation) { + liveTab = await liveTab.getContinuation() + videos = liveTab.videos + } + + this.latestLive = parseLocalChannelVideos(videos, this.id, this.channelName) this.liveContinuationData = liveTab.has_continuation ? liveTab : null this.isElementListLoading = false @@ -1053,7 +1051,7 @@ export default defineComponent({ showToast(`${errorMessage}: ${err}`, 10000, () => { copyToClipboard(err) }) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { showToast(this.$t('Falling back to Local API')) this.getChannelLocal() } else { @@ -1331,7 +1329,7 @@ export default defineComponent({ showToast(`${errorMessage}: ${err}`, 10000, () => { copyToClipboard(err) }) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { showToast(this.$t('Falling back to Local API')) if (!this.channelInstance) { this.channelInstance = await getLocalChannel(this.id) @@ -1372,7 +1370,7 @@ export default defineComponent({ showToast(`${errorMessage}: ${err}`, 10000, () => { copyToClipboard(err) }) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { showToast(this.$t('Falling back to Local API')) this.getChannelLocal() } else { @@ -1451,7 +1449,7 @@ export default defineComponent({ showToast(`${errorMessage}: ${err}`, 10000, () => { copyToClipboard(err) }) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { showToast(this.$t('Falling back to Local API')) if (!this.channelInstance) { this.channelInstance = await getLocalChannel(this.id) @@ -1485,7 +1483,7 @@ export default defineComponent({ showToast(`${errorMessage}: ${err}`, 10000, () => { copyToClipboard(err) }) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { showToast(this.$t('Falling back to Local API')) this.getChannelLocal() } else { @@ -1564,7 +1562,7 @@ export default defineComponent({ showToast(`${errorMessage}: ${err}`, 10000, () => { copyToClipboard(err) }) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { showToast(this.$t('Falling back to Local API')) if (!this.channelInstance) { this.channelInstance = await getLocalChannel(this.id) @@ -1598,7 +1596,7 @@ export default defineComponent({ showToast(`${errorMessage}: ${err}`, 10000, () => { copyToClipboard(err) }) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { showToast(this.$t('Falling back to Local API')) this.getChannelLocal() } else { @@ -1718,7 +1716,7 @@ export default defineComponent({ showToast(`${errorMessage}: ${err}`, 10000, () => { copyToClipboard(err) }) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { showToast(this.$t('Falling back to Local API')) if (!this.channelInstance) { this.channelInstance = await getLocalChannel(this.id) @@ -1927,6 +1925,7 @@ export default defineComponent({ } invidiousAPICall(payload).then((response) => { + setPublishedTimestampsInvidious(response.filter(item => item.type === 'video')) if (this.hideChannelPlaylists) { this.searchResults = this.searchResults.concat(response.filter(item => item.type !== 'playlist')) } else { @@ -1940,7 +1939,7 @@ export default defineComponent({ showToast(`${errorMessage}: ${err}`, 10000, () => { copyToClipboard(err) }) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { showToast(this.$t('Falling back to Local API')) this.searchChannelLocal() } else { diff --git a/src/renderer/views/Channel/Channel.vue b/src/renderer/views/Channel/Channel.vue index 687ab94a4..73b20664d 100644 --- a/src/renderer/views/Channel/Channel.vue +++ b/src/renderer/views/Channel/Channel.vue @@ -233,27 +233,27 @@ diff --git a/src/renderer/views/Hashtag/Hashtag.js b/src/renderer/views/Hashtag/Hashtag.js index b0edbff84..581b34f88 100644 --- a/src/renderer/views/Hashtag/Hashtag.js +++ b/src/renderer/views/Hashtag/Hashtag.js @@ -85,7 +85,7 @@ export default defineComponent({ showToast(`${errorMessage}: ${error}`, 10000, () => { copyToClipboard(error) }) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { showToast(this.$t('Falling back to Local API')) this.resetData() this.getLocalHashtag(hashtag) diff --git a/src/renderer/views/History/History.js b/src/renderer/views/History/History.js index ffa871ea2..0a494d7c5 100644 --- a/src/renderer/views/History/History.js +++ b/src/renderer/views/History/History.js @@ -93,11 +93,13 @@ export default defineComponent({ } else { const lowerCaseQuery = this.query.toLowerCase() const filteredQuery = this.historyCacheSorted.filter((video) => { - if (typeof (video.title) !== 'string' || typeof (video.author) !== 'string') { - return false - } else { - return video.title.toLowerCase().includes(lowerCaseQuery) || video.author.toLowerCase().includes(lowerCaseQuery) + if (typeof (video.title) === 'string' && video.title.toLowerCase().includes(lowerCaseQuery)) { + return true + } else if (typeof (video.author) === 'string' && video.author.toLowerCase().includes(lowerCaseQuery)) { + return true } + + return false }).sort((a, b) => { return b.timeWatched - a.timeWatched }) diff --git a/src/renderer/views/Playlist/Playlist.js b/src/renderer/views/Playlist/Playlist.js index 936f96abe..2dde53d0c 100644 --- a/src/renderer/views/Playlist/Playlist.js +++ b/src/renderer/views/Playlist/Playlist.js @@ -142,7 +142,13 @@ export default defineComponent({ if (this.processedVideoSearchQuery === '') { return this.playlistItems } return this.playlistItems.filter((v) => { - return v.title.toLowerCase().includes(this.processedVideoSearchQuery) + if (typeof (v.title) === 'string' && v.title.toLowerCase().includes(this.processedVideoSearchQuery)) { + return true + } else if (typeof (v.author) === 'string' && v.author.toLowerCase().includes(this.processedVideoSearchQuery)) { + return true + } + + return false }) }, visiblePlaylistItems: function () { @@ -307,7 +313,7 @@ export default defineComponent({ this.isLoading = false }).catch((err) => { console.error(err) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { console.warn('Error getting data with Invidious, falling back to local backend') this.getPlaylistLocal() } else { diff --git a/src/renderer/views/ProfileSettings/ProfileSettings.js b/src/renderer/views/ProfileSettings/ProfileSettings.js index 561f31918..6650d93f6 100644 --- a/src/renderer/views/ProfileSettings/ProfileSettings.js +++ b/src/renderer/views/ProfileSettings/ProfileSettings.js @@ -52,7 +52,7 @@ export default defineComponent({ methods: { openSettingsForNewProfile: function () { this.isNewProfileOpen = true - const bgColor = getRandomColor() + const bgColor = getRandomColor().value const textColor = calculateColorLuminance(bgColor) this.openSettingsProfile = { name: '', diff --git a/src/renderer/views/Search/Search.js b/src/renderer/views/Search/Search.js index 0e767e3fd..28ec65d5d 100644 --- a/src/renderer/views/Search/Search.js +++ b/src/renderer/views/Search/Search.js @@ -251,7 +251,7 @@ export default defineComponent({ showToast(`${errorMessage}: ${err}`, 10000, () => { copyToClipboard(err) }) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { showToast(this.$t('Falling back to Local API')) this.performSearchLocal(payload) } else { diff --git a/src/renderer/views/Settings/Settings.js b/src/renderer/views/Settings/Settings.js index f7dc155cd..9bc64c6a9 100644 --- a/src/renderer/views/Settings/Settings.js +++ b/src/renderer/views/Settings/Settings.js @@ -39,14 +39,11 @@ export default defineComponent({ }, data: function () { return { + usingElectron: process.env.IS_ELECTRON, unlocked: false } }, computed: { - usingElectron: function () { - return process.env.IS_ELECTRON - }, - settingsPassword: function () { return this.$store.getters.getSettingsPassword }, diff --git a/src/renderer/views/Trending/Trending.js b/src/renderer/views/Trending/Trending.js index d239a5a6d..355491b93 100644 --- a/src/renderer/views/Trending/Trending.js +++ b/src/renderer/views/Trending/Trending.js @@ -85,7 +85,7 @@ export default defineComponent({ this.$store.commit('clearTrendingCache') } - if (!process.env.IS_ELECTRON || this.backendPreference === 'invidious') { + if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious') { this.getTrendingInfoInvidious() } else { this.getTrendingInfoLocal() @@ -161,7 +161,7 @@ export default defineComponent({ copyToClipboard(err.responseText) }) - if (process.env.IS_ELECTRON && (this.backendPreference === 'invidious' && this.backendFallback)) { + if (process.env.SUPPORTS_LOCAL_API && (this.backendPreference === 'invidious' && this.backendFallback)) { showToast(this.$t('Falling back to Local API')) this.getTrendingInfoLocal() } else { diff --git a/src/renderer/views/UserPlaylists/UserPlaylists.js b/src/renderer/views/UserPlaylists/UserPlaylists.js index e4d7f3f28..1be2a9bdc 100644 --- a/src/renderer/views/UserPlaylists/UserPlaylists.js +++ b/src/renderer/views/UserPlaylists/UserPlaylists.js @@ -223,7 +223,7 @@ export default defineComponent({ if (typeof (playlist.playlistName) !== 'string') { return false } if (this.doSearchPlaylistsWithMatchingVideos) { - if (playlist.videos.some((v) => v.title.toLowerCase().includes(this.lowerCaseQuery))) { + if (playlist.videos.some((v) => v.author.toLowerCase().includes(this.lowerCaseQuery) || v.title.toLowerCase().includes(this.lowerCaseQuery))) { return true } } diff --git a/src/renderer/views/Watch/Watch.js b/src/renderer/views/Watch/Watch.js index ab9594f25..ceec92369 100644 --- a/src/renderer/views/Watch/Watch.js +++ b/src/renderer/views/Watch/Watch.js @@ -1,6 +1,5 @@ import { defineComponent } from 'vue' import { mapActions } from 'vuex' -import fs from 'fs/promises' import FtLoader from '../../components/ft-loader/ft-loader.vue' import FtVideoPlayer from '../../components/ft-video-player/ft-video-player.vue' import WatchVideoInfo from '../../components/watch-video-info/watch-video-info.vue' @@ -12,14 +11,12 @@ import WatchVideoPlaylist from '../../components/watch-video-playlist/watch-vide import WatchVideoRecommendations from '../../components/watch-video-recommendations/watch-video-recommendations.vue' import FtAgeRestricted from '../../components/ft-age-restricted/ft-age-restricted.vue' import packageDetails from '../../../../package.json' -import { pathExists } from '../../helpers/filesystem' import { buildVTTFileLocally, copyToClipboard, formatDurationAsTimestamp, formatNumber, getFormatsFromHLSManifest, - getUserDataPath, showToast } from '../../helpers/utils' import { @@ -141,9 +138,6 @@ export default defineComponent({ rememberHistory: function () { return this.$store.getters.getRememberHistory }, - removeVideoMetaFiles: function () { - return this.$store.getters.getRemoveVideoMetaFiles - }, saveWatchedProgress: function () { return this.$store.getters.getSaveWatchedProgress }, @@ -295,7 +289,7 @@ export default defineComponent({ this.checkIfPlaylist() this.checkIfTimestamp() - if (!process.env.IS_ELECTRON || this.backendPreference === 'invidious') { + if (!process.env.SUPPORTS_LOCAL_API || this.backendPreference === 'invidious') { this.getVideoInformationInvidious() } else { this.getVideoInformationLocal() @@ -703,7 +697,7 @@ export default defineComponent({ } if (result.storyboards?.type === 'PlayerStoryboardSpec') { - await this.createLocalStoryboardUrls(result.storyboards.boards.at(-1)) + this.createLocalStoryboardUrls(result.storyboards.boards.at(-1)) } } @@ -876,8 +870,8 @@ export default defineComponent({ this.audioTracks = [] this.dashSrc = await this.createInvidiousDashManifest() - if (process.env.IS_ELECTRON && this.audioTracks.length > 0) { - // when we are in Electron and the video has multiple audio tracks, + if (process.env.SUPPORTS_LOCAL_API && this.audioTracks.length > 0) { + // when the local API is supported and the video has multiple audio tracks, // we populate the list inside createInvidiousDashManifest // as we need to work out the different audio tracks for the DASH manifest anyway this.audioSourceList = this.audioTracks.find(track => track.isDefault).sourceList @@ -914,7 +908,7 @@ export default defineComponent({ copyToClipboard(err.responseText) }) console.error(err) - if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + if (process.env.SUPPORTS_LOCAL_API && this.backendPreference === 'invidious' && this.backendFallback) { showToast(this.$t('Falling back to Local API')) this.getVideoInformationLocal() } else { @@ -1239,7 +1233,7 @@ export default defineComponent({ copyToClipboard(err) }) console.error(err) - if (!process.env.IS_ELECTRON || (this.backendPreference === 'local' && this.backendFallback)) { + if (!process.env.SUPPORTS_LOCAL_API || (this.backendPreference === 'local' && this.backendFallback)) { showToast(this.$t('Falling back to Invidious API')) this.getVideoInformationInvidious() } @@ -1400,9 +1394,7 @@ export default defineComponent({ this.playNextCountDownIntervalId = setInterval(showCountDownMessage, 1000) }, - handleRouteChange: async function (videoId) { - // if the user navigates to another video, the ipc call for the userdata path - // takes long enough for the video id to have already changed to the new one + handleRouteChange: function (videoId) { // receiving it as an arg instead of accessing it ourselves means we always have the right one clearTimeout(this.playNextTimeout) @@ -1433,21 +1425,9 @@ export default defineComponent({ } } - if (process.env.IS_ELECTRON && this.removeVideoMetaFiles) { - if (process.env.NODE_ENV === 'development') { - const vttFileLocation = `static/storyboards/${videoId}.vtt` - // only delete the file it actually exists - if (await pathExists(vttFileLocation)) { - await fs.rm(vttFileLocation) - } - } else { - const userData = await getUserDataPath() - const vttFileLocation = `${userData}/storyboards/${videoId}.vtt` - - if (await pathExists(vttFileLocation)) { - await fs.rm(vttFileLocation) - } - } + if (this.videoStoryboardSrc.startsWith('blob:')) { + URL.revokeObjectURL(this.videoStoryboardSrc) + this.videoStoryboardSrc = '' } }, @@ -1491,7 +1471,7 @@ export default defineComponent({ // If we are in Electron, // we can use YouTube.js' DASH manifest generator to generate the manifest. // Using YouTube.js' gives us support for multiple audio tracks (currently not supported by Invidious) - if (process.env.IS_ELECTRON) { + if (process.env.SUPPORTS_LOCAL_API) { // Invidious' API response doesn't include the height and width (and fps and qualityLabel for AV1) of video streams // so we need to extract them from Invidious' manifest const response = await fetch(url) @@ -1612,36 +1592,14 @@ export default defineComponent({ }) }, - createLocalStoryboardUrls: async function (storyboardInfo) { + createLocalStoryboardUrls: function (storyboardInfo) { const results = buildVTTFileLocally(storyboardInfo, this.videoLengthSeconds) - const userData = await getUserDataPath() - let fileLocation - let uriSchema - // Dev mode doesn't have access to the file:// schema, so we access - // storyboards differently when run in dev - if (process.env.NODE_ENV === 'development') { - fileLocation = `static/storyboards/${this.videoId}.vtt` - uriSchema = `storyboards/${this.videoId}.vtt` - // if the location does not exist, writeFile will not create the directory, so we have to do that manually - if (!(await pathExists('static/storyboards/'))) { - fs.mkdir('static/storyboards/') - } else if (await pathExists(fileLocation)) { - await fs.rm(fileLocation) - } + // after the player migration, switch to using a data URI, as those don't need to be revoked - await fs.writeFile(fileLocation, results) - } else { - if (!(await pathExists(`${userData}/storyboards/`))) { - await fs.mkdir(`${userData}/storyboards/`) - } - fileLocation = `${userData}/storyboards/${this.videoId}.vtt` - uriSchema = `file://${fileLocation}` + const blob = new Blob([results], { type: 'text/vtt;charset=UTF-8' }) - await fs.writeFile(fileLocation, results) - } - - this.videoStoryboardSrc = uriSchema + this.videoStoryboardSrc = URL.createObjectURL(blob) }, tryAddingTranslatedLocaleCaption: function (captionTracks, locale, baseUrl) { diff --git a/static/external-player-map.json b/static/external-player-map.json index 2df522a82..81a976ece 100644 --- a/static/external-player-map.json +++ b/static/external-player-map.json @@ -1,13 +1,11 @@ [ { "name": "None", - "nameTranslationKey": "Settings.External Player Settings.Players.None.Name", "value": "", "cmdArguments": null }, { "name": "mpv", - "nameTranslationKey": "Settings.External Player Settings.Players.mpv.Name", "value": "mpv", "cmdArguments": { "defaultExecutable": "mpv", @@ -25,7 +23,6 @@ }, { "name": "VLC", - "nameTranslationKey": "Settings.External Player Settings.Players.VLC.Name", "value": "vlc", "cmdArguments": { "defaultExecutable": "vlc", @@ -43,7 +40,6 @@ }, { "name": "iina", - "nameTranslationKey": "Settings.External Player Settings.Players.iina.Name", "value": "iina", "cmdArguments": { "defaultExecutable": "iina", @@ -61,7 +57,6 @@ }, { "name": "SMPlayer", - "nameTranslationKey": "Settings.External Player Settings.Players.SMPlayer.Name", "value": "smplayer", "cmdArguments": { "defaultExecutable": "smplayer", @@ -79,7 +74,6 @@ }, { "name": "MPC-BE", - "nameTranslationKey": "Settings.External Player Settings.Players.MPC-BE.Name", "value": "mpc-be", "cmdArguments": { "defaultExecutable": "mpc-be64", @@ -97,7 +91,6 @@ }, { "name": "MPC-HC", - "nameTranslationKey": "Settings.External Player Settings.Players.MPC-HC.Name", "value": "mpc-hc", "cmdArguments": { "defaultExecutable": "mpc-hc64", @@ -115,7 +108,6 @@ }, { "name": "PotPlayer", - "nameTranslationKey": "Settings.External Player Settings.Players.PotPlayer.Name", "value": "potplayer", "cmdArguments": { "defaultExecutable": "potplayermini64", @@ -133,7 +125,6 @@ }, { "name": "Clapper", - "nameTranslationKey": "Settings.External Player Settings.Players.Clapper.Name", "value": "clapper", "cmdArguments": { "defaultExecutable": "clapper", @@ -151,7 +142,6 @@ }, { "name": "Celluloid", - "nameTranslationKey": "Settings.External Player Settings.Players.Celluloid.Name", "value": "celluloid", "cmdArguments": { "defaultExecutable": "celluloid", @@ -169,7 +159,6 @@ }, { "name": "Haruna", - "nameTranslationKey": "Settings.External Player Settings.Players.Haruna.Name", "value": "haruna", "cmdArguments": { "defaultExecutable": "haruna", diff --git a/static/invidious-instances.json b/static/invidious-instances.json index cc2607849..2f7e24209 100644 --- a/static/invidious-instances.json +++ b/static/invidious-instances.json @@ -8,11 +8,11 @@ "cors": true }, { - "url": "https://invidious.flokinet.to", + "url": "https://invidious.nerdvpn.de", "cors": true }, { - "url": "https://inv.bp.projectsegfau.lt", + "url": "https://invidious.projectsegfau.lt", "cors": true }, { @@ -20,11 +20,11 @@ "cors": true }, { - "url": "https://invidious.io.lol", + "url": "https://inv.tux.pizza", "cors": true }, { - "url": "https://inv.tux.pizza", + "url": "https://invidious.flokinet.to", "cors": true }, { @@ -32,19 +32,11 @@ "cors": true }, { - "url": "https://yt.artemislena.eu", + "url": "https://iv.ggtyler.dev", "cors": true }, { - "url": "https://vid.priv.au", - "cors": true - }, - { - "url": "https://onion.tube", - "cors": true - }, - { - "url": "https://yt.oelrichsgarcia.de", + "url": "https://inv.nadeko.net", "cors": true }, { @@ -52,29 +44,25 @@ "cors": true }, { - "url": "https://invidious.asir.dev", + "url": "https://iv.nboeck.de", "cors": true }, { - "url": "https://iv.nboeck.de", + "url": "https://yt.artemislena.eu", "cors": true }, { "url": "https://invidious.private.coffee", "cors": true }, + { + "url": "https://inv.n8pjl.ca", + "cors": true + }, { "url": "https://iv.datura.network", "cors": true }, - { - "url": "https://anontube.lvkaszus.pl", - "cors": true - }, - { - "url": "https://inv.us.projectsegfau.lt", - "cors": true - }, { "url": "https://invidious.perennialte.ch", "cors": true @@ -83,16 +71,20 @@ "url": "https://invidious.drgns.space", "cors": true }, + { + "url": "https://invidious.jing.rocks", + "cors": true + }, { "url": "https://invidious.einfachzocken.eu", "cors": true }, { - "url": "https://invidious.slipfox.xyz", + "url": "https://inv.oikei.net", "cors": true }, { - "url": "https://invidious.no-logs.com", + "url": "https://vid.lilay.dev", "cors": true }, { @@ -108,7 +100,7 @@ "cors": true }, { - "url": "https://inv.citw.lgbt", + "url": "https://invidious.privacyredirect.com", "cors": true } ] \ No newline at end of file diff --git a/static/locales/ar.yaml b/static/locales/ar.yaml index ba3d2397a..182f781fd 100644 --- a/static/locales/ar.yaml +++ b/static/locales/ar.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'العربية' -FreeTube: 'فري تيوب' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- هذا الجزء من التطبيق ليس جاهزاً بعد. عُد لاحقاً عندما يتم إحراز تقدم. @@ -399,7 +398,6 @@ Settings: أنت متأكد أنك تريد إزالة جميع الاشتراكات والملفات الشخصية؟ لا يمكن التراجع عن هذا. Remove All Subscriptions / Profiles: إزالة جميع الاشتراكات \ الملفات الشخصية - Automatically Remove Video Meta Files: إزالة ملفات تعريف الفيديو تلقائيًا Save Watched Videos With Last Viewed Playlist: حفظ مقاطع الفيديو التي تمت مشاهدتها مع آخر قائمة تشغيل تم عرضها All playlists have been removed: تمت إزالة جميع قوائم التشغيل @@ -1068,9 +1066,6 @@ Tooltips: Allow DASH AV1 formats: قد تبدو تنسيقات DASH AV1 أفضل من تنسيقات DASH H.264. تتطلب تنسيقات DASH AV1 مزيدا من الطاقة للتشغيل! وهي غير متوفرة في جميع مقاطع الفيديو ، وفي هذه الحالات سيستخدم المشغل تنسيقات DASH H.264 بدلا من ذلك. - Privacy Settings: - Remove Video Meta Files: عندما يمكن، يحذف Freetube تلقائيًا ملفات التعريف التي - تم إنشاؤها أثناء تشغيل الفيديو ، عندما تكون صفحة المشاهدة مغلقة. Subscription Settings: Fetch Feeds from RSS: عند تفعيلها، سوف يستخدم فريتيوب طريقة RSS بدلًا من طريقته المعتادة لجلب صفحة اشتراكاتك. طريقة RSS أسرع وتتخطى حجب الآي بي IP، لكنها لا @@ -1175,3 +1170,5 @@ Age Restricted: This channel is age restricted: هذه القناة مقيدة بالعمر This video is age restricted: هذا الفيديو مقيد بالفئة العمرية Close Banner: إغلاق الشعار +checkmark: ✓ +Display Label: '{label}: {value}' diff --git a/static/locales/as.yaml b/static/locales/as.yaml index 41018236f..c0d721131 100644 --- a/static/locales/as.yaml +++ b/static/locales/as.yaml @@ -1,4 +1,3 @@ -FreeTube: 'ফ্ৰীটিউব' # Currently on Subscriptions, Playlists, and History File: 'ফাইল' Quit: 'অন্ত কৰক' diff --git a/static/locales/be.yaml b/static/locales/be.yaml index 847311372..8eb66ff62 100644 --- a/static/locales/be.yaml +++ b/static/locales/be.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Беларуская' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Гэтая частка праграмы яшчэ не гатова. Прыходзьце пазней. @@ -307,7 +306,6 @@ Settings: Remember History: '' Save Watched Progress: '' Save Watched Videos With Last Viewed Playlist: '' - Automatically Remove Video Meta Files: '' Clear Search Cache: '' Are you sure you want to clear out your search cache?: '' Search cache has been cleared: '' @@ -802,8 +800,6 @@ Tooltips: Subscription Settings: Fetch Feeds from RSS: '' Fetch Automatically: '' - Privacy Settings: - Remove Video Meta Files: '' Experimental Settings: Replace HTTP Cache: '' SponsorBlock Settings: diff --git a/static/locales/bg.yaml b/static/locales/bg.yaml index e0454b566..c05dc3b1b 100644 --- a/static/locales/bg.yaml +++ b/static/locales/bg.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Български' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Тази част от приложението все още не е готова. Върнете се по-късно, когато може @@ -44,6 +43,8 @@ Global: Subscriber Count: 1 абонат | {count} абоната View Count: 1 преглед | {count} прегледа Watching Count: 1 гледане | {count} гледания + Input Tags: + Length Requirement: Дължината на етикета трябва да бъде поне {number} знака Version {versionNumber} is now available! Click for more details: 'Версия {versionNumber} е вече налична! Щракнете за повече детайли' Download From Site: 'Сваляне от сайта' @@ -127,7 +128,7 @@ User Playlists: изброени само видеа, които сте запазили или избрали за предпочитани. Когато работата приключи, всички видеа, които в момента са тук, ще бъдат преместени в плейлист „Предпочитани“. - Search bar placeholder: Търсене в плейлиста + Search bar placeholder: Търсене за плейлисти Empty Search Message: В този плейлист няма видеа, които да отговарят на търсенето ви This playlist currently has no videos.: В този плейлист в момента няма видеа. @@ -166,6 +167,7 @@ User Playlists: This playlist is protected and cannot be removed.: Този плейлист е защитен и не може да бъде премахнат. This playlist does not exist: Този плейлист не съществува + Search for Videos: Търсене за видеа CreatePlaylistPrompt: Toast: Playlist {playlistName} has been successfully created.: Плейлиста {playlistName} @@ -207,6 +209,7 @@ User Playlists: към {playlistCount} плейлиста | Добавени {videoCount} видеа към {playlistCount} плейлиста Save: Запазване + Added {count} Times: Добавено {count} път | Добавено {count} пъти Remove from Playlist: Премахване от плейлиста за изпълнение Playlist Name: Име на плейлиста Save Changes: Запазване на промените @@ -218,6 +221,7 @@ User Playlists: Delete Playlist: Изтриване на плейлиста Remove from Favorites: Премахване от {playlistName} Move Video Down: Преместване надолу + Playlists with Matching Videos: Плейлисти със съвпадащи видеа History: # On History Page History: 'История' @@ -287,6 +291,7 @@ Settings: Catppuccin Mocha: Catppuccin Mocha Pastel Pink: Пастелно розово Hot Pink: Горещо розово + Nordic: Nordic Main Color Theme: Main Color Theme: 'Основна цветова тема' Red: 'Червено' @@ -409,7 +414,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Сигурни ли сте, че искате да премахнете всички абонаменти и профили? Това не може да бъде възстановено.' - Automatically Remove Video Meta Files: Автоматично премахване на видео метафайловете Save Watched Videos With Last Viewed Playlist: Запазване на гледани видеа с последно гледан плейлист Remove All Playlists: Премахване на всички плейлисти @@ -528,7 +532,7 @@ Settings: Hide Channels: Скриване видеата от каналите Hide Channels Placeholder: Идентификатор на канала Display Titles Without Excessive Capitalisation: Показване на заглавията без излишни - главни букви + главни букви и препинателни знаци Hide Featured Channels: Скриване на препоръчаните канали Hide Channel Playlists: Скриване на плейлистите на каналите Hide Channel Community: Скриване на общността на каналите @@ -553,6 +557,10 @@ Settings: идентификатор. Моля, проверете отново дали идентификаторът е правилен. Hide Channels Invalid: Предоставеният идентификатор на канала е невалиден Hide Channels Already Exists: Идентификаторът на канала вече съществува + Hide Videos and Playlists Containing Text: Скриване на видеа и плейлисти, съдържащи + текст + Hide Videos and Playlists Containing Text Placeholder: Дума, част от дума или + фраза The app needs to restart for changes to take effect. Restart and apply change?: Приложението трябва да се рестартира за да се приложат промените. Рестартиране? Proxy Settings: @@ -780,6 +788,7 @@ Channel: votes: '{votes} гласа' Reveal Answers: Разкриване на отговорите Hide Answers: Скриване на отговорите + Video hidden by FreeTube: Видео, скрито от FreeTube This channel does not exist: Каналът не съществува This channel does not allow searching: Каналът не позволява търсене This channel is age-restricted and currently cannot be viewed in FreeTube.: Каналът @@ -866,7 +875,7 @@ Video: Upcoming: 'Премиера на' Less than a minute: По-малко от минута In less than a minute: След по-малко от минута - Published on: 'Публикуван на' + Published on: 'Публикувано на' Publicationtemplate: 'Преди {number} {unit}' #& Videos Audio: @@ -944,6 +953,7 @@ Video: Pause on Current Video: Пауза на текущото видео Unhide Channel: Показване на канала Hide Channel: Скриване на канала + More Options: Още опции Videos: #& Sort By Sort By: @@ -1087,10 +1097,6 @@ Tooltips: External Link Handling: "Избор на поведението по подразбиране, когато щракнете върху връзка, която не може да бъде отворена във FreeTube.\nПо подразбиране FreeTube ще отвори връзката в браузъра по подразбиране.\n" - Privacy Settings: - Remove Video Meta Files: Когато страницата за гледане бъде затворена, FreeTube - автоматично ще изтрива метафайловете, създадени по време на възпроизвеждане - на видеото. External Player Settings: Custom External Player Arguments: Всички персонализирани аргументи от командния ред, разделени с точка и запетая (";"), които искате да бъдат предадени на външния @@ -1119,6 +1125,10 @@ Tooltips: и малки букви. Hide Subscriptions Live: Тази настройка се отменя от настройката за цялото приложение "{appWideSetting}" в секция "{subsection}" на "{settingsSection}" + Hide Videos and Playlists Containing Text: Въведете дума, част от дума или фраза + (без значение от главни и малки букви), за да скриете всички видеа и плейлисти, + чиито оригинални заглавия ги съдържат в целия FreeTube, с изключение само на + Историята, Вашите плейлисти и видеата в плейлистите. SponsorBlock Settings: UseDeArrowTitles: Заменя заглавията на видеата с подадени от потребителите заглавия от DeArrow. @@ -1179,3 +1189,10 @@ Playlist will not pause when current video is finished: Плейлистът н Channel Hidden: '{channel} е добавен към филтъра за канали' Channel Unhidden: '{channel} е премахнат от филтъра за канали' Go to page: Отиване на {page} +Tag already exists: Етикетът "{tagName}" вече съществува +Trimmed input must be at least N characters long: Орязаният вход трябва да бъде дълъг + поне 1 символ | Орязаният вход трябва да бъде дълъг поне {length} символа +Age Restricted: + This channel is age restricted: Този канал е с възрастово ограничение + This video is age restricted: Това видео е с възрастово ограничение +Close Banner: Затваряне на банер diff --git a/static/locales/bn.yaml b/static/locales/bn.yaml index 82cb20bef..26612f6b1 100644 --- a/static/locales/bn.yaml +++ b/static/locales/bn.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'বাংলা' -FreeTube: 'ফ্রিটিউব' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- অ্যাপের এই অংশটি এখনও প্রস্তুত নয়। পরে ফিরে এসো যখন অগ্রগতি হয়েছে। diff --git a/static/locales/bs.yaml b/static/locales/bs.yaml index 5104e2b0c..f9d3f065e 100644 --- a/static/locales/bs.yaml +++ b/static/locales/bs.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Bosanski' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Ovaj dio aplikacije još nije spreman. Vratite se kasnije kad se postigne napredak. diff --git a/static/locales/ca.yaml b/static/locales/ca.yaml index 6d0627144..4b1c91366 100644 --- a/static/locales/ca.yaml +++ b/static/locales/ca.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'català' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Aquesta secció de l'aplicació encara no està llesta. Torna més endavant quan s'hagin @@ -266,8 +265,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Esteu segur que voleu esborrar totes les subscripcions i perfils? Aquesta acció no es pot desfer.' - Automatically Remove Video Meta Files: Suprimeix automàticament les metadades - dels vídeos Subscription Settings: Subscription Settings: 'Configuració de les subscripcions' Hide Videos on Watch: 'Oculta els vídeos visualitzats' diff --git a/static/locales/ckb.yaml b/static/locales/ckb.yaml index 10df3f5a8..a3a269e5b 100644 --- a/static/locales/ckb.yaml +++ b/static/locales/ckb.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'ئیگلیزی (وڵاتە یەکگرتووەکانی ئەمریکا)' -FreeTube: 'فریتیوب' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- بەشێک لە نەرمەواڵەکە هێشتا ئامادە نییە. کە ڕەوتەکە درووست کرا دووبارە وەرەوە. @@ -311,7 +310,6 @@ Settings: Remember History: '' Save Watched Progress: '' Save Watched Videos With Last Viewed Playlist: '' - Automatically Remove Video Meta Files: '' Clear Search Cache: '' Are you sure you want to clear out your search cache?: '' Search cache has been cleared: '' @@ -818,8 +816,6 @@ Tooltips: Subscription Settings: Fetch Feeds from RSS: '' Fetch Automatically: '' - Privacy Settings: - Remove Video Meta Files: '' Experimental Settings: Replace HTTP Cache: '' SponsorBlock Settings: diff --git a/static/locales/cs.yaml b/static/locales/cs.yaml index 9aa0f5e78..e257e56b2 100644 --- a/static/locales/cs.yaml +++ b/static/locales/cs.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Čeština' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Tato část aplikace ještě není hotova. Vraťte se později. @@ -411,7 +410,6 @@ Settings: Remove All Subscriptions / Profiles: 'Odstranit všechny odběry / profily' Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Opravdu chcete odstranit všechny odběry a profily? Tato akce je nevratná.' - Automatically Remove Video Meta Files: Automaticky odstranit meta soubory videa Save Watched Videos With Last Viewed Playlist: Uložit zhlédnutá videa s naposledy zobrazeným playlistem All playlists have been removed: Všechny playlisty byly odstraněny @@ -1057,9 +1055,6 @@ Tooltips: # Toast Messages Fetch Automatically: Při povolení tohoto nastavení bude FreeTube automaticky načítat vaše odběry při otevření nového okna a při přepínání profilů. - Privacy Settings: - Remove Video Meta Files: Pokud je povoleno, FreeTube automaticky odstraní meta - soubory vytvořené během přehrávání videa, když se stránka sledování zavře. External Player Settings: Ignore Warnings: Potlačuje varování, kdy současný externí přehrávač nepodporuje aktuální akci (např. obrácení seznamů skladeb apod.). @@ -1173,3 +1168,5 @@ Close Banner: Zavřít panel Age Restricted: This channel is age restricted: Tento kanál je omezen věkem This video is age restricted: Toto video je omezeno věkem +checkmark: ✓ +Display Label: '{label}: {value}' diff --git a/static/locales/cy.yaml b/static/locales/cy.yaml index 6f277d93c..d4b3349b4 100644 --- a/static/locales/cy.yaml +++ b/static/locales/cy.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Cymraeg' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': > @@ -314,7 +313,6 @@ Settings: Remember History: 'Cadw Hanes' Save Watched Progress: '' Save Watched Videos With Last Viewed Playlist: '' - Automatically Remove Video Meta Files: '' Clear Search Cache: '' Are you sure you want to clear out your search cache?: '' Search cache has been cleared: '' @@ -820,8 +818,6 @@ Tooltips: Subscription Settings: Fetch Feeds from RSS: '' Fetch Automatically: '' - Privacy Settings: - Remove Video Meta Files: '' Experimental Settings: Replace HTTP Cache: '' SponsorBlock Settings: diff --git a/static/locales/da.yaml b/static/locales/da.yaml index e9033f2dc..690b45739 100644 --- a/static/locales/da.yaml +++ b/static/locales/da.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'dansk' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Denne del af app'en er ikke klar endnu. Kom tilbage senere, når der er gjort fremskridt. @@ -383,7 +382,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Er du sikker på, at du vil fjerne alle abonnementer og profiler? Dette kan ikke fortrydes.' - Automatically Remove Video Meta Files: Fjern Automatisk Video Metafiler All playlists have been removed: Alle playlister blev fjernet Are you sure you want to remove all your playlists?: Er du sikker på, at du vil fjerne alle dine playlister? @@ -1010,9 +1008,6 @@ Tooltips: Advarsel: Invidious-indstillinger har ingen effekt på eksterne afspillere.' Ignore Warnings: Undertryk advarsler for når den eksterne afspiller ikke understøtter den gældende handling (fx vende playlister om, etc.). - Privacy Settings: - Remove Video Meta Files: Når det er aktiveret, sletter FreeTube automatisk metafiler - oprettet under videoafspilning, når siden lukkes. Distraction Free Settings: Hide Channels: Indtast et kanal-ID for at skjule alle videoer, playlister og selve kanalen fra at blive vist i søgning, trending, mest populære og anbefalet. Det diff --git a/static/locales/de-DE.yaml b/static/locales/de-DE.yaml index 10f816214..217c6772b 100644 --- a/static/locales/de-DE.yaml +++ b/static/locales/de-DE.yaml @@ -1,4 +1,3 @@ -FreeTube: FreeTube # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Dieser Teil der App ist noch nicht bereit. Komme später wieder, wenn Fortschritte @@ -461,7 +460,6 @@ Settings: du sicher, dass du alle Abos und Profile löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden. Remove All Subscriptions / Profiles: Alle Abos / Profile entfernen - Automatically Remove Video Meta Files: Video-Metadateien automatisch entfernen Save Watched Videos With Last Viewed Playlist: Angesehene Videos mit der zuletzt angesehenen Wiedergabeliste speichern Remove All Playlists: Alle Wiedergabelisten entfernen @@ -1140,10 +1138,6 @@ Tooltips: Die DASH AV1-Formate benötigen mehr Leistung für die Wiedergabe! Sie sind nicht bei allen Videos verfügbar. In diesen Fällen verwendet der Abspieler stattdessen die DASH H.264-Formate. - Privacy Settings: - Remove Video Meta Files: Wenn aktiviert, löscht FreeTube automatisch die während - der Videowiedergabe erstellten Metadateien, wenn die Abspielseite geschlossen - wird. External Player Settings: Custom External Player Arguments: Alle benutzerdefinierten Befehlszeilenargumente, getrennt durch Semikolon (';'), die an den externen Abspieler übergeben werden @@ -1249,3 +1243,5 @@ Close Banner: Banner schließen Age Restricted: This channel is age restricted: Dieser Kanal ist altersbeschränkt This video is age restricted: Dieses Video ist altersbeschränkt +Display Label: '{label}: {value}' +checkmark: ✓ diff --git a/static/locales/el.yaml b/static/locales/el.yaml index 31e8a2fe0..4ff90643e 100644 --- a/static/locales/el.yaml +++ b/static/locales/el.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Ελληνικά (EL)' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Αυτό το μέρος της εφαρμογής δεν είναι ακόμη έτοιμο. Επιστρέψτε αργότερα όταν έχει @@ -323,7 +322,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Είστε βέβαιοι ότι θέλετε να καταργήσετε όλες τις συνδρομές και τα προφίλ; Αυτό δεν μπορεί να αναιρεθεί.' - Automatically Remove Video Meta Files: Αυτόματη αφαίρεση μετα-αρχείων βίντεο Save Watched Videos With Last Viewed Playlist: Αποθήκευση Βίντεο που Παρακολουθήσατε Με τη Λίστα Αναπαραγωγής Τελευταίας Προβολής Subscription Settings: @@ -1019,10 +1017,6 @@ Tooltips: σε έναν σύνδεσμο, ο οποίος δεν μπορεί να ανοίξει στο FreeTube.\nΑπό προεπιλογή, το FreeTube θα ανοίξει τον σύνδεσμο που έχει πατηθεί στο προεπιλεγμένο πρόγραμμα περιήγησης.\n" - Privacy Settings: - Remove Video Meta Files: Όταν είναι ενεργοποιημένο, το FreeTube διαγράφει αυτόματα - τα μετα-αρχεία που δημιουργήθηκαν κατά την αναπαραγωγή βίντεο, όταν η σελίδα - παρακολούθησης είναι κλειστή. External Player Settings: Custom External Player Executable: Από προεπιλογή, το FreeTube θα υποθέσει ότι το επιλεγμένο εξωτερικό πρόγραμμα αναπαραγωγής μπορεί να βρεθεί μέσω της μεταβλητής diff --git a/static/locales/en-US.yaml b/static/locales/en-US.yaml index 60f91e356..75eef565a 100644 --- a/static/locales/en-US.yaml +++ b/static/locales/en-US.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: English (US) -FreeTube: FreeTube # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- This part of the app is not ready yet. Come back later when progress has been made. @@ -413,7 +412,6 @@ Settings: Remember History: Remember History Save Watched Progress: Save Watched Progress Save Watched Videos With Last Viewed Playlist: Save Watched Videos With Last Viewed Playlist - Automatically Remove Video Meta Files: Automatically Remove Video Meta Files Clear Search Cache: Clear Search Cache Are you sure you want to clear out your search cache?: Are you sure you want to clear out your search cache? @@ -1003,9 +1001,6 @@ Tooltips: but doesn't provide certain information like video duration or live status Fetch Automatically: When enabled, FreeTube will automatically fetch your subscription feed when a new window is opened and when switching profile. - Privacy Settings: - Remove Video Meta Files: When enabled, FreeTube automatically deletes meta files created during video playback, - when the watch page is closed. Experimental Settings: Replace HTTP Cache: Disables Electron's disk based HTTP cache and enables a custom in-memory image cache. Will lead to increased RAM usage. SponsorBlock Settings: @@ -1060,3 +1055,7 @@ Hashtag: Yes: Yes No: No Ok: Ok +# symbol used to indicate that an item is correct +checkmark: ✓ +# French is the only language that should change this (they have a space before the colon) +Display Label: '{label}: {value}' diff --git a/static/locales/en_GB.yaml b/static/locales/en_GB.yaml index 81ff39260..1c9d112fc 100644 --- a/static/locales/en_GB.yaml +++ b/static/locales/en_GB.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'English (UK)' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- This part of the app is not ready yet. Come back later when progress has been made. @@ -417,7 +416,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Are you sure you want to remove all subscriptions and profiles? This cannot be undone.' - Automatically Remove Video Meta Files: Automatically Remove Video Meta Files Save Watched Videos With Last Viewed Playlist: Save Watched Videos With Last Viewed Playlist Remove All Playlists: Remove all playlists @@ -1084,9 +1082,6 @@ Tooltips: Custom External Player Arguments: Any custom command line arguments, separated by semicolons (';'), you want to be passed to the external player. DefaultCustomArgumentsTemplate: '(Default: ‘{defaultCustomArguments}’)' - Privacy Settings: - Remove Video Meta Files: When enabled, FreeTube automatically deletes meta files - created during video playback, when the watch page is closed. Experimental Settings: Replace HTTP Cache: Disables Electron's disk-based HTTP cache and enables a custom in-memory image cache. Will lead to increased RAM usage. diff --git a/static/locales/eo.yaml b/static/locales/eo.yaml index fea50e47c..461dcf747 100644 --- a/static/locales/eo.yaml +++ b/static/locales/eo.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Esperanto' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History File: 'Dosiero' Quit: 'Eliri' diff --git a/static/locales/es-MX.yaml b/static/locales/es-MX.yaml index 61ee2146e..ef30b4b58 100644 --- a/static/locales/es-MX.yaml +++ b/static/locales/es-MX.yaml @@ -1,4 +1,3 @@ -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Esta parte de la aplicación aún no está lista. Vuelva más tarde cuando se haya avanzado. @@ -290,7 +289,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: ¿Estás seguro de que deseas eliminar todos los suscripciones y perfiles? Esto no puede ser deshecho. - Automatically Remove Video Meta Files: Borrar automáticamente metadatos del video Data Settings: How do I import my subscriptions?: ¿Cómo puedo importar mis suscripciones? Export History: Exportar Historia @@ -796,9 +794,6 @@ Tooltips: presionada la tecla Ctrl (tecla Comando en Mac) y haga clic izquierdo para reestablecer la velocidad de reproducción predeterminada (que es de 1x, a menos que la haya cambiado en configuración). - Privacy Settings: - Remove Video Meta Files: Si se habilita, FreeTube borrará automáticamente los - metadatos creados al abrir el video, una vez que la ventana se cierre. Subscription Settings: Fetch Feeds from RSS: Si se habilita, FreeTube usará RSS en lugar del método predeterminado para recibir videos de sus suscripciones. RSS es más rápido y previene que bloqueen diff --git a/static/locales/es.yaml b/static/locales/es.yaml index 68e45bc0e..37becae32 100644 --- a/static/locales/es.yaml +++ b/static/locales/es.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'español (España)' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Esta parte de la aplicación aún no está lista. Vuelve más tarde cuando se hayan @@ -413,8 +412,6 @@ Settings: Remove All Subscriptions / Profiles: 'Borrar todas las suscripciones/perfiles' Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: '¿Confirma que quieres borrar todas las suscripciones y perfiles? Esta operación es irreversible.' - Automatically Remove Video Meta Files: Eliminar automáticamente los metadatos - de vídeos Save Watched Videos With Last Viewed Playlist: Guardar vídeos vistos con la última lista de reproducción vista All playlists have been removed: Se han eliminado todas las listas de reproducción @@ -1113,10 +1110,6 @@ Tooltips: External Link Handling: "Elija el comportamiento por defecto cuando se hace clic en un enlace que no se pueda abrirse en FreeTube. \nPor defecto, FreeTube abrirá el enlace en el que se hizo clic en su navegador predeterminado.\n" - Privacy Settings: - Remove Video Meta Files: Cuando se active, FreeTube eliminará automáticamente - meta-archivos creados durante la reproducción del vídeo una vez se cierre la - página de visualizado. External Player Settings: Custom External Player Executable: Por defecto, FreeTube buscará el reproductor externo seleccionado mediante la variable de entorno PATH, de no encontrarlo, @@ -1219,3 +1212,5 @@ Close Banner: Cerrar el banner Age Restricted: This channel is age restricted: Este canal está restringido por edad This video is age restricted: Este vídeo está restringido por edad +checkmark: ✓ +Display Label: '{label}: {value}' diff --git a/static/locales/es_AR.yaml b/static/locales/es_AR.yaml index f3de05dc3..3a4908e12 100644 --- a/static/locales/es_AR.yaml +++ b/static/locales/es_AR.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'español (Argentina)' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Esta parte de la aplicación no esta lista por el momento. Vuelve después cuando @@ -111,6 +110,11 @@ User Playlists: Search bar placeholder: Buscar en la Lista de Reproducción Empty Search Message: No hay videos en esta lista de reproducción que coincidan con tu búsqueda + This playlist currently has no videos.: Esta lista de reproducción no tiene videos. + Playlists with Matching Videos: Listas de reproducción con videos repetidos + Create New Playlist: Crear nueva lista de reproducción + Add to Favorites: Añadir a {playlistName} + Add to Playlist: Añadir a la lista de reproducción History: # On History Page History: 'Historial' @@ -296,7 +300,6 @@ Settings: Remove All Subscriptions / Profiles: 'Remover todas las suscripciones / perfiles' Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: '¿Realmente querés remover todas las suscripciones y perfiles? Esta acción no puede deshacerse.' - Automatically Remove Video Meta Files: Borrar automáticamente metadatos del video Save Watched Videos With Last Viewed Playlist: Guardar videos vistos con la última lista de reproducción vista Subscription Settings: @@ -489,3 +492,5 @@ Tooltips: Distraction Free Settings: Hide Subscriptions Live: Esta configuración se reemplaza por la configuración «{appWideSetting}» de toda la aplicación, en la sección «{subsection}» de «{settingsSection}» +Go to page: Ir a {page} +Close Banner: Cerrar banner diff --git a/static/locales/et.yaml b/static/locales/et.yaml index 122c2ccce..f0fe96b12 100644 --- a/static/locales/et.yaml +++ b/static/locales/et.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'eesti keel' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Rakenduse see osa pole veel valmis. Tule hiljem tagasi, kui arendustööd on valmis. @@ -245,7 +244,7 @@ Settings: Invidious API: 'API Invidious''e veebirakenduses' Video View Type: Video View Type: 'Kasutatav videote vaade' - Grid: 'Võrgustik' + Grid: 'Ruudustik' List: 'Loend' Thumbnail Preference: Thumbnail Preference: 'Pisipiltide eelistus' @@ -344,7 +343,7 @@ Settings: Turn on Subtitles by Default: 'Vaikimisi näita subtiitreid' Autoplay Videos: 'Esita videod automaatselt' Proxy Videos Through Invidious: 'Puhverda videosid Invidious''e veebiteenuse kaudu' - Autoplay Playlists: 'Automaatselt mängi esitusloendit' + Autoplay Playlists: 'Mängi esitusloendit automaatselt' Enable Theatre Mode by Default: 'Vaikimisi kasuta teatrivaadet (laia vaadet)' Default Volume: 'Vaikimisi helivaljus' Default Playback Rate: 'Vaikimisi videoesituse kiirus' @@ -392,7 +391,7 @@ Settings: Allow DASH AV1 formats: Luba DASH AV1 vormingud Enter Fullscreen on Display Rotate: Ekraani pööramisel ava täisekraanivaade Comment Auto Load: - Comment Auto Load: Kommentaaride automaatne laadimine + Comment Auto Load: Laadi kommentaarid automaatselt Privacy Settings: Privacy Settings: 'Privaatsuse seadistused' Remember History: 'Jäta ajalugu meelde' @@ -409,7 +408,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Kas sa oled kindel, et soovid kustutada kõik tellimused/profiilid? Seda tegevust ei saa tagasi pöörata.' - Automatically Remove Video Meta Files: Automaatselt kustuta videote metateave Save Watched Videos With Last Viewed Playlist: Salvesta vaadatud videod viimati vaadatud videote esitusloendisse All playlists have been removed: Kõik esitusloendid on eemaldatud @@ -576,7 +574,7 @@ Settings: Ignore Default Arguments: Eira vaikimisi käsureaargumente Download Settings: Download Settings: Allalaadimise seadistused - Ask Download Path: Küsi kausta, kuhu soovid faile alla laadida + Ask Download Path: Küsi kuhu kausta soovid faile alla laadida Choose Path: Vali asukoht Download Behavior: Tegevus allalaadimisel Open in web browser: Ava veebibrauseris @@ -998,7 +996,7 @@ Tooltips: on leitav PATH keskkonnamuutuja alusel. Aga kui vaja, siis saad siin seadistada muu asukoha. Ignore Warnings: Kui väline meediamängija antud funktsionaalsust (näiteks esitusloendi - järjekorra pööramine) ei toeta siis ära näita hoiatusi. + järjekorra pööramine) ei toeta, siis ära näita hoiatusi. Custom External Player Arguments: Semikoolonitega (;) eraldatud käsurea argumendid, mida sa soovid välisele meediamängijale saata. External Player: "Seadistades välise meediamängija kuvame pisipildil ikooni video @@ -1014,9 +1012,6 @@ Tooltips: IP-aadressi blokeerimise, kuid ei sisalda video kestust ja otseesituse olekut Fetch Automatically: Kui see valik on kasutusel, siis FreeTube automaatselt laadib uue akna avamisel ja profiili vahetamisel sinu tellimuste loendi. - Privacy Settings: - Remove Video Meta Files: Selle valiku kasutamisel FreeTube automaatselt kustutab - peale video esitamist kogu metateabe. General Settings: Region for Trending: Piirkond, mille alusel kuvame hetkel menukad ehk populaarsust koguvad videod. @@ -1128,3 +1123,5 @@ Age Restricted: This channel is age restricted: Kanali vaatamisel on vanusepiirang This video is age restricted: Video vaatamisel on vanusepiirang Close Banner: Sulge rekaampilt +checkmark: ✓ +Display Label: '{label}: {value}' diff --git a/static/locales/eu.yaml b/static/locales/eu.yaml index 03e2d3a88..eec7a47a5 100644 --- a/static/locales/eu.yaml +++ b/static/locales/eu.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Euskera' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Zati hau ez dago prest oraindik. Itzuli aurrerago aurrerapenak egin direnean. @@ -400,7 +399,6 @@ Settings: Privacy Settings: 'Pribatutasunari buruzko ezarpenak' Remember History: 'Historikoa oroitu' Save Watched Progress: 'Ikusitakoaren progresioa gorde' - Automatically Remove Video Meta Files: 'Bideo metafitxategiak ezabatu automatikoki' Clear Search Cache: 'Bilaketen cachea ezabatu' Are you sure you want to clear out your search cache?: 'Ziur al zaude bilaketa-cachea garbitu nahi duzula?' @@ -1019,10 +1017,6 @@ Tooltips: bideoaren iraupenaren informaziorik ez du ematen, besteak beste' Fetch Automatically: Gaituta dagoenean, FreeTubek automatikoki eskuratuko du zure harpidetza-jarioa leiho berri bat irekitzen denean eta profila aldatzean. - Privacy Settings: - Remove Video Meta Files: 'Gaituta dagoenean, FreeTube-k automatikoki ezabatzen - ditu bideoen erreprodukzioan sortutako metafitxategiak, bistaratze orria ixten - denean.' # Toast Messages External Player Settings: diff --git a/static/locales/fa.yaml b/static/locales/fa.yaml index 7d62641c5..b96647d65 100644 --- a/static/locales/fa.yaml +++ b/static/locales/fa.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'فارسی (ایرانی)' -FreeTube: 'یوتیوب آزاد' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- این بخش از نرم افزار هنوز آماده نیست.زمانی که پیشرفتی صورت گرفت به اینجا باز گردید. @@ -290,8 +289,6 @@ Settings: Privacy Settings: 'تنظیمات امنیتی' Remember History: 'حفظ تاریخچه' Save Watched Progress: 'ذخیره ویدیو های دیده شده' - Automatically Remove Video Meta Files: 'به صورت خودکار متا فایل های ویدیو را حذف - کردن' Clear Search Cache: 'پاک کردن کش جستجو' Are you sure you want to clear out your search cache?: 'آیا مطمئن هستید که میخواهید کش جستجویتان را پاک کنید؟' @@ -702,9 +699,6 @@ Tooltips: نمی دهد Fetch Automatically: هنگامی که فعال باشد، FreeTube به طور خودکار فید اشتراک شما را هنگام باز شدن یک پنجره جدید و هنگام تغییر نمایه دریافت می کند. - Privacy Settings: - Remove Video Meta Files: هنگامی که FreeTube فعال باشد، به طور خودکار فایل های - متا ایجاد شده در حین پخش ویدیو را حذف می کند، زمانی که صفحه تماشا بسته می شود. External Player Settings: Custom External Player Executable: به طور پیش فرض، FreeTube فرض می کند که پخش کننده خارجی انتخاب شده را می توان از طریق متغیر محیطی PATH پیدا کرد. در صورت diff --git a/static/locales/fi.yaml b/static/locales/fi.yaml index 9fab29925..cbe0b3a78 100644 --- a/static/locales/fi.yaml +++ b/static/locales/fi.yaml @@ -1,4 +1,3 @@ -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Tämä sovelluksen osa ei ole vielä valmis. Tule takaisin myöhemmin kun olemme edistyneet. @@ -144,6 +143,8 @@ User Playlists: ja sitä ei voi poistaa. Playlist {playlistName} has been deleted.: Soittolista {playlistName} on poistettu. This playlist does not exist: Soittolistaa ei ole olemassa + There was an issue with updating this playlist.: Tätä soittolistaa päivittäessä + ilmeni ongelma. Search for Videos: Etsi videot Move Video Down: Siirrä video alas Remove from Playlist: Poista soittolistalta @@ -174,6 +175,8 @@ User Playlists: nimellä on jo olemassa soittolista. Valitse eri nimi. Playlist {playlistName} has been successfully created.: Soittolista {playlistName} on luotu. + There was an issue with creating the playlist.: Soittolistaa luotaessa ilmeni + ongelma. Add to Favorites: Lisää soittolistaan {playlistName} Remove from Favorites: Poista soittolistalta {playlistName} Remove Watched Videos: Poista katsotut videot @@ -363,6 +366,7 @@ Settings: How do I import my subscriptions?: 'Miten voin tuoda tilaukseni?' Fetch Feeds from RSS: Nouda RSS-syöte Fetch Automatically: Nouda syöte automaattisesti + Only Show Latest Video for Each Channel: Näytä vain jokaisen kanavan uusin video Advanced Settings: Advanced Settings: 'Lisäasetukset' Enable Debug Mode (Prints data to the console): 'Ota virheenkorjaustila käyttöön @@ -404,7 +408,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: Haluatko cvarmasti poistaa kaikki tilaukset ja profiilit. Tätä toimintoa ei voi perua. Remove All Subscriptions / Profiles: Poista kaikki tilaukset / profiilit - Automatically Remove Video Meta Files: Poista videoiden metadata automaattisesti Save Watched Videos With Last Viewed Playlist: Tallenna katsotut videot viimeksi katsotulla soittolistalla Remove All Playlists: Poista kaikki soittolistat @@ -458,6 +461,8 @@ Settings: Playlist File: Soittolistatiedosto History File: Historia-tiedosto Subscription File: Tilaustiedosto + Export Playlists For Older FreeTube Versions: + Label: Vie soittolistat FreeTuben vanhempiin versioihin Distraction Free Settings: Hide Live Chat: Piilota Live-keskustelu Hide Popular Videos: Piilota suositut videot @@ -570,6 +575,7 @@ Settings: Password Settings: Salasana-asetukset Set Password: Aseta salasana Remove Password: Poista salasana + Expand All Settings Sections: Laajenna asetusten kaikki osiot About: #On About page About: 'Tietoja' @@ -1013,9 +1019,6 @@ Tooltips: H.264 formaatit. DASH AV1 formaatit vaativat enemmän tehoa toistamiseen! Ne eivät ole käytettävissä kaikissa videoissa ja näissä tapauksissa soitin käyttää sen sijaan DASH H.264 formaatteja. - Privacy Settings: - Remove Video Meta Files: Kun tämä on kytkettynä päälle, FreeTube poistaa automaattisesti - meta-tiedostot jotka luotiin videon toiston aikana, katselusivu suljettaessa. External Player Settings: Custom External Player Arguments: Kaikki ne omavalintaiset komentorivin määreet, puolipisteillä eroteltuina (';'), jotka haluat siirtää eteenpäin ulkoiselle diff --git a/static/locales/fil.yaml b/static/locales/fil.yaml index 294cef1be..311fb54a3 100644 --- a/static/locales/fil.yaml +++ b/static/locales/fil.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Filipino' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Ang bahagi ito ng aplikasyon ay hindi pa handa. Bumalik po kayo mamaya kapag nag-unsad diff --git a/static/locales/fr-FR.yaml b/static/locales/fr-FR.yaml index 7c580fa99..c7941965d 100644 --- a/static/locales/fr-FR.yaml +++ b/static/locales/fr-FR.yaml @@ -1,4 +1,3 @@ -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Cette partie de l'application n'est pas encore prête. Revenez plus tard lorsque @@ -471,8 +470,6 @@ Settings: sûr(e) de vouloir supprimer tous les abonnements et les profils ? Cette action est définitive. Remove All Subscriptions / Profiles: Supprimer tous les Abonnements / Profils - Automatically Remove Video Meta Files: Supprimer automatiquement les métafichiers - vidéo Save Watched Videos With Last Viewed Playlist: Sauvegarder les vidéos regardées avec la dernière liste de lecture vue All playlists have been removed: Toutes les listes de lecture ont été supprimées @@ -1159,10 +1156,6 @@ Tooltips: External Link Handling: "Choisissez le comportement par défaut quand on clique sur un lien qui ne peut être ouvert dans FreeTube.\nPar défaut, FreeTube ouvrira le lien dans votre navigateur par défaut.\n" - Privacy Settings: - Remove Video Meta Files: Lorsqu'il est activé, FreeTube supprime automatiquement - les MétaFichiers créés pendant la lecture de la vidéo, dès que la page de la - vidéo est quittée. External Player Settings: Custom External Player Arguments: Tous les arguments de ligne de commande personnalisés, séparés par des points-virgules (';'), que vous souhaitez transmettre au lecteur @@ -1269,3 +1262,6 @@ Age Restricted: This channel is age restricted: Cette chaîne est soumise à des restrictions d'âge This video is age restricted: Cette vidéo est soumise à des restrictions d'âge Close Banner: Fermer la bannière +# French is the only language that should change this (they have a space before the colon) +Display Label: '{label} : {value}' +checkmark: ✓ diff --git a/static/locales/gl.yaml b/static/locales/gl.yaml index fd4cf960d..a0c694502 100644 --- a/static/locales/gl.yaml +++ b/static/locales/gl.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'galego' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Esta parte da aplicación non está lista aínda. Volve máis adiante, cando se avance @@ -305,8 +304,6 @@ Settings: Remove All Subscriptions / Profiles: 'Limpar tódalas subscricións / perfís' Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Estás seguro de querer limpar tódalas subscricións e perfís? Esta acción é irreversible.' - Automatically Remove Video Meta Files: Elimina automaticamente os ficheiros meta - de vídeo Save Watched Videos With Last Viewed Playlist: Gardalos vídeos vistos coa última lista de reprodución vista Subscription Settings: @@ -883,10 +880,6 @@ Tooltips: # Toast Messages Fetch Automatically: Cando estea activado, FreeTube buscará automaticamente o teu feed da subscrición, cando se abra unha nova ventá e cando cambies de perfil. - Privacy Settings: - Remove Video Meta Files: Cando está activado, FreeTube elimina automaticamente - os ficheiros meta creados durante a reprodución de vídeo cando a páxina de visualización - está pechada. External Player Settings: Custom External Player Arguments: Calquera argumento de liña de comandos personalizado, separado por puntos e coma (';'), que desexa que se pase ao reprodutor externo. diff --git a/static/locales/gsw.yaml b/static/locales/gsw.yaml index e964dc53a..182e20a50 100644 --- a/static/locales/gsw.yaml +++ b/static/locales/gsw.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Schwiizerdütsch' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- De Teil vom Programm isch nonig fertig. Bitte chum zumene spötere Ziitpunkt wider diff --git a/static/locales/he.yaml b/static/locales/he.yaml index 2f88b67fc..29fcd35a3 100644 --- a/static/locales/he.yaml +++ b/static/locales/he.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'עברית' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- החלק הזה ביישומון עדיין לא מוכן. מזמינים אותך לשוב ולבדוק בהמשך כשנתקדם. @@ -307,7 +306,6 @@ Settings: Remove All Subscriptions / Profiles: 'למחק את כל המינויים / פרופילים' Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'למחוק כל את המינויים והפרופילים? זופעולה בלתי הפיכה.' - Automatically Remove Video Meta Files: להסיר אוטומטית קובצי נתוני על של הסרטון Save Watched Videos With Last Viewed Playlist: לשמור את הסרטונים שנצפו עם רשימת הנגינה לאחרונים שנצפו Subscription Settings: @@ -943,9 +941,6 @@ Tooltips: נגיש דרך משתנה הסביבה PATH. במקרה הצורך, ניתן להגדיר כאן נתיב משלך. Custom External Player Arguments: הארגומנטים משלך לשורת הפקודה שיועברו לנגן החיצוני, מופרדים בפסיקים (‚;’). - Privacy Settings: - Remove Video Meta Files: כאשר אפשרות זו מופעלת, FreeTube מוחק באופן אוטומטי קובצי - על שנוצרים במהלך ניגון סרטון, לאחר סגירת עמוד הצפייה. Experimental Settings: Replace HTTP Cache: משבית את מטמון ה־HTTP מבוסס הכונן ומפעיל מטמון תמונות מותאם אישית בזיכרון. יגדיל את צריכת הזיכרון (RAM). diff --git a/static/locales/hi.yaml b/static/locales/hi.yaml index 240dbb83f..707c61dd4 100644 --- a/static/locales/hi.yaml +++ b/static/locales/hi.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'English (US)' -FreeTube: 'फ्रीट्यूब' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- ऐप का यह हिस्सा अभी तैयार नहीं है। बाद में वापस आएँ जब प्रगति हुई हो diff --git a/static/locales/hr.yaml b/static/locales/hr.yaml index f2aa89c7a..1bcb4c36b 100644 --- a/static/locales/hr.yaml +++ b/static/locales/hr.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Hrvatski' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Ovaj dio programa još nije gotov. Navrati kasnije. @@ -401,8 +400,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: Stvarno želiš ukloniti sve pretplate i profile? Ovo je nepovratna radnja. Remove All Subscriptions / Profiles: Ukloni sve pretplate/profile - Automatically Remove Video Meta Files: Automatski ukloni datoteke metapodataka - videa Save Watched Videos With Last Viewed Playlist: Spremi gledana videa sa zadnjim gledanom zbirkom Remove All Playlists: Ukloni sve zbirke @@ -1095,10 +1092,6 @@ Tooltips: ili stanja „uživo” Fetch Automatically: Kada je aktivirano, FreeTube će automatski dohvatiti feed tvoje pretplate kada se otvori novi prozor i prilikom mijenjanja profila. - Privacy Settings: - Remove Video Meta Files: Kada je aktivirano, FreeTube automatski uklanja datoteke - metapodataka koji su stvoreni tijekom reprodukcije videa, kad se zatvori stranica - gledanja. External Player Settings: External Player: Biranjem vanjskog playera prikazat će se ikona, za otvaranje videa (zbirka, ako je podržana) u vanjskom playeru, na minijaturi. Upozorenje, diff --git a/static/locales/hu.yaml b/static/locales/hu.yaml index dd8796701..78ef6b5d4 100644 --- a/static/locales/hu.yaml +++ b/static/locales/hu.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Magyar' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Az alkalmazás ezen része még nem áll készen. Térjen vissza később amikor előrelépés @@ -422,7 +421,6 @@ Settings: Remove All Subscriptions / Profiles: 'Összes feliratkozás és profil eltávolítása' Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Biztosan törli az összes feliratkozást és profilt? A művelet nem vonható vissza.' - Automatically Remove Video Meta Files: Videó-metafájlok automatikus eltávolítása Save Watched Videos With Last Viewed Playlist: Megtekintett videók mentése az utoljára megtekintett lejátszási listával All playlists have been removed: Minden lejátszási lista eltávolításra került @@ -1109,9 +1107,6 @@ Tooltips: H.264 formátumok. A DASH AV1 formátumok több energiát igényelnek a lejátszáshoz! Nem minden videónál érhetők el, ilyenkor a lejátszó a DASH H.264 formátumot használja helyette. - Privacy Settings: - Remove Video Meta Files: Ha engedélyezve van, a FreeTube automatikusan törli a - videolejátszás során létrehozott metafájlokat, amikor a nézőlapot bezárják. External Player Settings: Custom External Player Executable: Alapértelmezés szerint a FreeTube feltételezi, hogy a kiválasztott külső lejátszó megtalálható a PATH (ÚTVONAL) környezeti @@ -1211,3 +1206,5 @@ Close Banner: Banner bezárása Age Restricted: This channel is age restricted: Ez a csatorna korhatáros This video is age restricted: Ez a videó korhatáros +Display Label: '{label}: {value}' +checkmark: ✓ diff --git a/static/locales/id.yaml b/static/locales/id.yaml index b471e1b32..9f5bca8ba 100644 --- a/static/locales/id.yaml +++ b/static/locales/id.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Bahasa Indonesia' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Bagian dari aplikasi ini belum disiapkan. Kembali lagi nanti saat kemajuan telah @@ -280,7 +279,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Apakah Anda yakin ingin menghapus semua langganan dan profil? Tindakan ini tidak bisa diurungkan.' - Automatically Remove Video Meta Files: Secara Otomatis Hapus File Meta Video Subscription Settings: Subscription Settings: 'Pengaturan Langganan' Hide Videos on Watch: 'Sembunyikan Video saat Menonton' @@ -809,9 +807,6 @@ Tooltips: External Link Handling: "Pilih perilaku default ketika tautan, yang tidak dapat dibuka di FreeTube, diklik.\nSecara default FreeTube akan membuka tautan yang diklik dengan browser default Anda.\n" - Privacy Settings: - Remove Video Meta Files: Saat diaktifkan, FreeTube secara otomatis menghapus file - meta yang dibuat selama pemutaran video, saat halaman tonton ditutup. External Player Settings: Custom External Player Arguments: Semua argumen perintah khusus, dipisahkan dengan titik koma (';'), yang Anda ingin gunakan dengan pemutar eksternal. diff --git a/static/locales/is.yaml b/static/locales/is.yaml index 5434496d6..943454280 100644 --- a/static/locales/is.yaml +++ b/static/locales/is.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Íslenska' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Þessi hluti forritsins er ekki tilbúinn. Skoðaðu þetta seinna þegar meira hefur @@ -416,7 +415,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Ertu viss um að þú viljir fjarlægja allar áskriftir og notkunarsnið? Ekki er hægt að afturkalla þetta.' - Automatically Remove Video Meta Files: Sjálfvirkt fjarlægja lýsigögn úr myndskeiðaskrám Save Watched Videos With Last Viewed Playlist: Vista myndskeið sem horft var á með síðast notaða spilunarlista Remove All Playlists: Fjarlægja alla spilunarlista @@ -1027,9 +1025,6 @@ Tooltips: # Toast Messages Fetch Automatically: Þegar þetta er virkt, mun FreeTube sækja sjálfkrafa áskriftarstreymin þín þegar nýr gluggi er opnaður og þegar skipt er um notkunarsnið. - Privacy Settings: - Remove Video Meta Files: Þegar þetta er virkt, eyðir FreeTube sjálfkrafa lýsigagnaskrám - sem útbúnar eru við afspilun, þegar skoðunarsíðunni er lokað. External Player Settings: Custom External Player Arguments: Öll sérsniðin skipanaviðföng og rofar, aðskilin með semíkommum (';'), sem beina á til utanaðkomandi spilarans. diff --git a/static/locales/it.yaml b/static/locales/it.yaml index e32e30e45..89abfd207 100644 --- a/static/locales/it.yaml +++ b/static/locales/it.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Italiano' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Questa parte dell'app non è ancora pronta. Torna più tardi quando saranno stati @@ -412,8 +411,6 @@ Settings: sicuro di volere eliminare tutte le iscrizioni e i profili? L'operazione non può essere annullata. Remove All Subscriptions / Profiles: Elimina tutte le iscrizioni e i profili - Automatically Remove Video Meta Files: Rimuovi automaticamente i metafile dai - video Save Watched Videos With Last Viewed Playlist: Salva i video guardati con l'ultima playlist vista All playlists have been removed: Tutte le playlist sono state rimosse @@ -1135,10 +1132,6 @@ Tooltips: Ignore Default Arguments: Non inviare argomenti predefiniti al lettore esterno oltre all'URL del video (ad esempio velocità di riproduzione, URL della playlist, ecc.). Gli argomenti personalizzati verranno comunque trasmessi. - Privacy Settings: - Remove Video Meta Files: Se abilitato, quando chiuderai la pagina di riproduzione - , FreeTube eliminerà automaticamente i metafile creati durante la visione del - video . Experimental Settings: Replace HTTP Cache: Disabilita la cache HTTP basata su disco Electron e abilita una cache di immagini in memoria personalizzata. Comporta un aumento dell'uso @@ -1222,3 +1215,5 @@ Age Restricted: This video is age restricted: Questo video è soggetto a limiti di età This channel is age restricted: Questo canale è soggetto a limiti di età Close Banner: Chiudi banner +checkmark: ✓ +Display Label: '{label}: {value}' diff --git a/static/locales/ja.yaml b/static/locales/ja.yaml index f851625cb..943362756 100644 --- a/static/locales/ja.yaml +++ b/static/locales/ja.yaml @@ -1,4 +1,3 @@ -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- アプリのこの部分は未完成です。完成後に実行してください。 @@ -110,7 +109,7 @@ Playlists: '再生リスト' User Playlists: Your Playlists: 'あなたの再生リスト' Your saved videos are empty. Click on the save button on the corner of a video to have it listed here: 保存した動画はありません。一覧に表示させるには、ビデオの角にある保存ボタンをクリックします - Playlist Message: + Playlist Message: このページは、完全に動作する動画リストではありません。保存またはお気に入りと設定した動画のみが表示されます。操作が完了すると、現在ここにあるすべての動画は「お気に入り」の動画リストに移動します。 Search bar placeholder: 動画リスト内の検索 Empty Search Message: この再生リストに、検索に一致する動画はありません @@ -332,7 +331,6 @@ Settings: Privacy Settings: 個人情報の設定 Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: すべての登録チャンネルとプロファイルを削除しますか?元に戻せません。 Remove All Subscriptions / Profiles: 登録とプロファイルをすべて削除 - Automatically Remove Video Meta Files: 動画のメタファイルの自動削除 Save Watched Videos With Last Viewed Playlist: 「最後に再生した」リストで視聴済み動画を保存 Data Settings: How do I import my subscriptions?: 私の登録情報を取り込むにはどうしたらいいですか? @@ -469,7 +467,7 @@ Settings: Experimental Settings: Replace HTTP Cache: HTTP キャッシュの置換 Experimental Settings: 実験中の設定 - Warning: + Warning: これらの設定は実験的なものであり、有効にするとアプリのクラッシュを引き起こす恐れがあります。バックアップをとっておくことを強くお勧めします。自己責任で使用してください! Password Settings: Password Settings: パスワード設定 @@ -882,8 +880,6 @@ Tooltips: Region for Trending: 急上昇の地域設定では、急上昇動画を表示する国を選択できます。 External Link Handling: "FreeTube で開けないリンクをクリックしたときのデフォルトの動作を選択します。\nデフォルトでは、FreeTube はクリックしたリンクをデフォルトのブラウザで開きます。\n" - Privacy Settings: - Remove Video Meta Files: 有効にすると、FreeTube は動画再生中に作成したメタファイルを、再生ページを閉じるときに自動的に削除します。 External Player Settings: Custom External Player Arguments: '";"、セミコロンで区切られたカスタム コマンド ライン引数を外部プレーヤーに渡します。' Ignore Warnings: 現在の外部プレーヤーが、現在のアクションに未対応の場合(動画リストの反転など)に警告を抑制します。 diff --git a/static/locales/ka.yaml b/static/locales/ka.yaml index e5c0b9f5e..3cee0eead 100644 --- a/static/locales/ka.yaml +++ b/static/locales/ka.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'ქართული ენა' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- აპლიკაციის ეს ნაწილი ჯერ არ არის მზად. გთხოვთ, შეამოწმოთ მოგვიანებით, როდესაც იქნება diff --git a/static/locales/km.yaml b/static/locales/km.yaml index 8e3988d77..6c2106edc 100644 --- a/static/locales/km.yaml +++ b/static/locales/km.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'ភាសាខ្មែរ' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- ផ្នែកនេះនៃកម្មវិធីមិនទាន់រួចរាល់នៅឡើយទេ។ ត្រលប់មកវិញនៅពេលក្រោយ ពេលដែលវឌ្ឍនភាពត្រូវបានបង្កើតឡើង។ diff --git a/static/locales/ko.yaml b/static/locales/ko.yaml index 48ab70bc0..4fd3d4d10 100644 --- a/static/locales/ko.yaml +++ b/static/locales/ko.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: '한국어' -FreeTube: '프리튜브' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- 아직 구현 되지 않은 기능입니다. 개발이 완료된 후 다시 시도해주세요. @@ -286,7 +285,6 @@ Settings: Remove All Subscriptions / Profiles: '모든 구독채널과 프로필 삭제' Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: '정말로 모든 구독채널과 프로필을 삭제하시겠습니까? 삭제하면 복구가되지않습니다.' - Automatically Remove Video Meta Files: 비디오 메타 파일 자동 제거 Subscription Settings: Subscription Settings: '구독 설정' Hide Videos on Watch: '시청한 동영상 숨기기' @@ -752,9 +750,6 @@ Tooltips: Ignore Warnings: '현재 외부 플레이어가 현재 작업을 지원하지 않는 경우(예: 재생 목록 반전 등) 경고를 표시하지 않습니다.' Custom External Player Arguments: 외부 플레이어로 전달되기를 원하는사용자 지정 명령줄 인수는 세미콜론(';')으로 구분됩니다. - Privacy Settings: - Remove Video Meta Files: 활성화되면 FreeTube는 보기 페이지가 닫힐 때 비디오 재생 중에 생성된 메타 파일을 자동으로 - 삭제합니다. Distraction Free Settings: Hide Channels: 채널 이름이나 채널 ID를 입력해 해당 채널의 영상이나 재생목록, 채널 자체가 검색이나 인기 영상에 나타나지 않도록 합니다. 입력되는 채널 이름은 완전히 일치해야하며, 대소문자를 구별합니다. diff --git a/static/locales/ku.yaml b/static/locales/ku.yaml index 1879548c3..a0278df86 100644 --- a/static/locales/ku.yaml +++ b/static/locales/ku.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'کوردی ناوەڕاست' -FreeTube: 'فریتیوب' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- ئە بەشە لە ئەپلیکەیشنەکە هێشتا بەردەست نییە. لە کاتێکی دواتردا وەرەوە کە پێشکەوتنێک diff --git a/static/locales/la.yaml b/static/locales/la.yaml index ae7803694..e4b20b5a2 100644 --- a/static/locales/la.yaml +++ b/static/locales/la.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Latina' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Haec programmatis pars perfecta non est. Remea cum in hac profectum sit. diff --git a/static/locales/lt.yaml b/static/locales/lt.yaml index 47fd7d1ba..e51e8028a 100644 --- a/static/locales/lt.yaml +++ b/static/locales/lt.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'lietuvių' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Ši programėlės dalis dar neparengta. Grįžkite vėliau, kai bus padaryta pažanga. @@ -311,8 +310,6 @@ Settings: Privacy Settings: 'Privatumo nustatymai' Remember History: 'Įsiminti istoriją' Save Watched Progress: 'Išsaugoti peržiūros progresą' - Automatically Remove Video Meta Files: 'Automatiškai pašalinti vaizdo įrašų meta - failus' Clear Search Cache: 'Išvalyti paieškos talpyklą' Are you sure you want to clear out your search cache?: 'Ar tikrai norite išvalyti paieškos talpyklą?' @@ -832,9 +829,6 @@ Tooltips: trukmės ar tiesioginės transliacijos būsenos' Fetch Automatically: Kai ši funkcija įjungta, FreeTube automatiškai įkels naują turinį iš prenumeratų, kai atidaromas naujas langas ir perjungiamas profilis. - Privacy Settings: - Remove Video Meta Files: 'Įjungus FreeTube, uždarius žiūrėjimo puslapį, automatiškai - ištrinami meta failai, sukurti vaizdo atkūrimo metu.' # Toast Messages Experimental Settings: diff --git a/static/locales/lv.yaml b/static/locales/lv.yaml index 130bb3cbf..3bb50c420 100644 --- a/static/locales/lv.yaml +++ b/static/locales/lv.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Latviešu' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': > @@ -309,7 +308,6 @@ Settings: Remember History: 'Atcerēties vēsturi' Save Watched Progress: 'Saglabāt skatīto attīstību' Save Watched Videos With Last Viewed Playlist: '' - Automatically Remove Video Meta Files: 'Automātiski noņemt video metadatus' Clear Search Cache: '' Are you sure you want to clear out your search cache?: '' Search cache has been cleared: '' @@ -817,8 +815,6 @@ Tooltips: Subscription Settings: Fetch Feeds from RSS: '' Fetch Automatically: '' - Privacy Settings: - Remove Video Meta Files: '' Experimental Settings: Replace HTTP Cache: '' SponsorBlock Settings: diff --git a/static/locales/nb_NO.yaml b/static/locales/nb_NO.yaml index 86ec5a9de..f6dc91f41 100644 --- a/static/locales/nb_NO.yaml +++ b/static/locales/nb_NO.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Norsk bokmål' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Denne delen av programmet er ikke klart enda. Kom tilbake senere når ting er i orden. @@ -295,7 +294,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: Er du sikker på at du vil fjerne alle abonnementer og profiler? Dette kan ikke angres. - Automatically Remove Video Meta Files: Fjern metadata automatisk fra videoer Save Watched Videos With Last Viewed Playlist: Lagre sette videoer med sist sette spilleliste Subscription Settings: @@ -888,9 +886,6 @@ Tooltips: Allow DASH AV1 formats: DASH AV1-formater kan ha bedre kvalitet enn DASH H.264 -formater. DASH AV1-formater krever dog mer regnekraft for avspilling. Ikke tilgjengelig for alle videoer, og i sådant fall bruker avspilleren DASH H.264-formater. - Privacy Settings: - Remove Video Meta Files: Hvis denne instillingen er på, vil FreeTube automatisk - slette metadata generert under videoavspilling når du lukker avspillingsiden. External Player Settings: Custom External Player Arguments: Alle egendefinerte kommandolinjeargumenter, semikoloninndelt («;») du ønsker å sende til den eksterne avspilleren. @@ -968,3 +963,4 @@ Hashtag: Hashtag: Emneknagg This hashtag does not currently have any videos: Denne emneknaggen har ingen videoer enda +checkmark: ✓ diff --git a/static/locales/ne.yaml b/static/locales/ne.yaml index 9a8ad74bd..88cb5e274 100644 --- a/static/locales/ne.yaml +++ b/static/locales/ne.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'नेपाली' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- एपको यो भाग अझै तयार भएको छैन। केहि प्रगति भएपछि आउनु होला। diff --git a/static/locales/nl.yaml b/static/locales/nl.yaml index 5c179f0bd..fa04a58a3 100644 --- a/static/locales/nl.yaml +++ b/static/locales/nl.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Nederlands' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Dit gedeelte van de app is nog niet klaar. Kom later terug als er vooruitgang is @@ -409,8 +408,6 @@ Settings: u zeker dat u alle abonnementen en profielen wil verwijderen? Dit kan niet ongedaan worden gemaakt. Remove All Subscriptions / Profiles: Verwijder alle abonnementen / profielen - Automatically Remove Video Meta Files: Bestanden met metadata van video's automatisch - verwijderen Save Watched Videos With Last Viewed Playlist: Houd bekeken video's bij met de afspeellijst ‘Laatst bekeken’ Remove All Playlists: Alle afspeel­lijsten verwijderen @@ -1108,10 +1105,6 @@ Tooltips: External Link Handling: "Kies het standaard gedrag voor wanneer een link dat niet kan worden geopend in FreeTube is aangeklikt.\nStandaard zal FreeTube de aangeklikte link openen in je standaardbrowser.\n" - Privacy Settings: - Remove Video Meta Files: Wanneer ingeschakeld zal FreeTube automatisch meta bestanden - die worden gecreëerd tijdens het afspelen van video's verwijderen zodra de pagina - wordt gesloten. External Player Settings: Custom External Player Arguments: Aangepaste opdrachtregelargumenten, gescheiden door puntkomma's (';'), die je wil doorgeven aan de externe videospeler. @@ -1211,3 +1204,5 @@ Age Restricted: This video is age restricted: Deze video heeft een leeftijds­beperking Trimmed input must be at least N characters long: Bij­gesneden invoer moet minimaal 1 teken lang zijn | Bij­gesneden invoer moet minimaal {length} tekens lang zijn +checkmark: ✓ +Display Label: '{label}: {value}' diff --git a/static/locales/nn.yaml b/static/locales/nn.yaml index 8e454d553..f08b5d593 100644 --- a/static/locales/nn.yaml +++ b/static/locales/nn.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Norsk nynorsk' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Denne delen av programmet er ikkje klar enda. Ver venleg og kom tilbake på eit seinare @@ -298,7 +297,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Er du sikker på at du vil fjerne alle abonnentar og profil? Dette kan ikkje bli ugjort.' - Automatically Remove Video Meta Files: Fjern metadata automatisk frå videoar Subscription Settings: Subscription Settings: 'Abonnementinnstillingar' Hide Videos on Watch: 'Skjul sette videoar' @@ -798,9 +796,6 @@ Tooltips: # Toast Messages Fetch Automatically: Om dette alternativet er aktivert, vil FreeTube automatisk hente abonnementfeeden din når eit nytt vindauge opnast og når du bytter profil. - Privacy Settings: - Remove Video Meta Files: Viss denne innstillinga er på, vil FreeTube automatisk - slette metadata generert under videoavspeling når du lukker avspelingsida. External Player Settings: DefaultCustomArgumentsTemplate: "(Standard: '{defaultCustomArguments}')" Custom External Player Executable: Som standard vil FreeTube anta at den valte diff --git a/static/locales/pl.yaml b/static/locales/pl.yaml index a2d05fed6..355170d1d 100644 --- a/static/locales/pl.yaml +++ b/static/locales/pl.yaml @@ -1,4 +1,3 @@ -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Ta część aplikacji nie jest jeszcze gotowa. Wróć później, gdy zostaną poczynione @@ -454,7 +453,6 @@ Settings: jesteś pewny/a, że chcesz usunąć wszystkie subskrypcje i profile? Nie będzie można tego cofnąć. Remove All Subscriptions / Profiles: Usuń wszystkie subskrypcje / profile - Automatically Remove Video Meta Files: Automatycznie usuwaj pliki metadanych filmu Save Watched Videos With Last Viewed Playlist: Zapisuj do historii film wraz z ostatnią odtwarzaną playlistą, która go zawierała All playlists have been removed: Wszystkie playlisty zostały usunięte @@ -528,7 +526,7 @@ Settings: Hide Video Likes And Dislikes: Schowaj łapki w górę i w dół Hide Video Views: Schowaj wyświetlenia filmów Hide Active Subscriptions: Schowaj aktywne subskrypcje - Hide Playlists: Schowaj playlistę + Hide Playlists: Schowaj playlisty Hide Video Description: Schowaj opis filmu Hide Comments: Schowaj komentarze Hide Sharing Actions: Schowaj linki do dzielenia się filmem @@ -1121,9 +1119,6 @@ Tooltips: H.264 DASH. Dekodowanie formatu AV1 DASH wymaga większej mocy obliczeniowej. W filmach, dla których ten format nie jest dostępny, zostanie użyty format H.264 DASH. - Privacy Settings: - Remove Video Meta Files: Po włączeniu FreeTube automatycznie usunie pliki metadanych - utworzone podczas odtwarzania filmu, gdy strona odtwarzacza zostanie zamknięta. External Player Settings: Ignore Warnings: Nie pokazuj ostrzeżeń o nieobsługiwanych akcjach przez zewnętrzny odtwarzacz (n.p. odwracanie playlist, itp.). @@ -1225,3 +1220,5 @@ Age Restricted: This video is age restricted: Ten film ma ograniczenie wiekowe This channel is age restricted: Ten kanał ma ograniczenie wiekowe Close Banner: Zamknij Baner +checkmark: ✓ +Display Label: '{label}: {value}' diff --git a/static/locales/pt-BR.yaml b/static/locales/pt-BR.yaml index db2ac3841..405a77063 100644 --- a/static/locales/pt-BR.yaml +++ b/static/locales/pt-BR.yaml @@ -1,4 +1,3 @@ -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Esta parte do aplicativo ainda não está pronta. Volte mais tarde quando o progresso @@ -208,7 +207,7 @@ User Playlists: Select a playlist to add your N videos to: Selecione uma playlist para adicionar seu vídeo | Selecione uma playlist para adicionar seus {videoCount} vídeos N playlists selected: '{playlistCount} selecionada(s)' - Search in Playlists: Pesquisar nas playlists + Search in Playlists: Buscar nas playlists Save: Salvar Added {count} Times: Adicionado {count} vez | Adicionado {count} vezes Are you sure you want to remove all watched videos from this playlist? This cannot be undone: Tem @@ -232,7 +231,7 @@ Settings: em caso de falha' Enable Search Suggestions: 'Habilitar sugestões de pesquisa' Default Landing Page: 'Página inicial preferida' - Locale Preference: 'Preferência de localização' + Locale Preference: 'Idioma' Preferred API Backend: Preferred API Backend: 'API de processamento preferida' Local API: 'API local' @@ -242,7 +241,7 @@ Settings: Grid: 'Em grade' List: 'Em lista' Thumbnail Preference: - Thumbnail Preference: 'Preferência por miniaturas' + Thumbnail Preference: 'Preferências de miniaturas' Default: 'Normal' Beginning: 'No começo' Middle: 'No meio' @@ -251,7 +250,7 @@ Settings: Blur: Desfocar 'Invidious Instance (Default is https://invidious.snopyta.org)': 'Instância do Invidious (A padrão é https://invidious.snopyta.org)' - Region for Trending: 'Região da Tendência' + Region for Trending: 'Região' #! List countries Check for Updates: Buscar por atualizações Check for Latest Blog Posts: Verificar se há novas postagens no blog @@ -270,10 +269,10 @@ Settings: No Action: Nenhuma ação Ask Before Opening Link: Perguntar antes de abrir o link Open Link: Abrir link - External Link Handling: Tratamento de link externo + External Link Handling: Ação de link externo Theme Settings: Theme Settings: 'Configurações de aparência' - Match Top Bar with Main Color: 'Usar a cor principal para a barra superior' + Match Top Bar with Main Color: 'Usar cor principal na barra superior' Base Theme: Base Theme: 'Tema base' Black: 'Preto' @@ -332,7 +331,7 @@ Settings: Hide Side Bar Labels: Ocultar título na barra lateral Hide FreeTube Header Logo: Ocultar logotipo FreeTube na barra superior Player Settings: - Player Settings: 'Configurações do player' + Player Settings: 'Configurações de reprodução' Force Local Backend for Legacy Formats: 'Forçar processamento local para formatos antigos' Remember History: 'Lembrar do histórico' @@ -364,10 +363,10 @@ Settings: Playlist Next Video Interval: Intervalo do próximo vídeo da lista de reprodução Next Video Interval: Próximo intervalo de vídeo Display Play Button In Video Player: Mostrar botão "Reproduzir" no centro do player - Scroll Volume Over Video Player: Alterar volume sobre o player de vídeo + Scroll Volume Over Video Player: Alterar volume ao rolar sobre o player Fast-Forward / Rewind Interval: Intervalo de avanço / retrocesso rápido - Scroll Playback Rate Over Video Player: Alterar taxa de reprodução sobre o player - de vídeo + Scroll Playback Rate Over Video Player: Alterar taxa de reprodução ao rolar sobre + o player Max Video Playback Rate: Taxa máxima de reprodução de vídeo Video Playback Rate Interval: Intervalo da taxa de reprodução de vídeo Screenshot: @@ -406,8 +405,8 @@ Settings: How do I import my subscriptions?: 'Como posso importar minhas inscrições?' Fetch Feeds from RSS: Buscar Informações através de RSS Fetch Automatically: Buscar feed automaticamente - Only Show Latest Video for Each Channel: Exibe apenas vídeo mais recente de cada - canal + Only Show Latest Video for Each Channel: Mostrar apenas vídeo mais recente para + cada canal Advanced Settings: Advanced Settings: 'Configurações avançadas' Enable Debug Mode (Prints data to the console): 'Habilitar modo de depuração (Mostra @@ -451,8 +450,6 @@ Settings: certeza de que deseja remover todas as inscrições e perfis? Isto não pode ser desfeito. Remove All Subscriptions / Profiles: Remover todas as inscrições ou perfis - Automatically Remove Video Meta Files: Remover automaticamente os metarquivos - de vídeo Save Watched Videos With Last Viewed Playlist: Salvar vídeos assistidos com a última playlist visualizada All playlists have been removed: Todas as playlists foram removidas @@ -542,7 +539,7 @@ Settings: Sections: Side Bar: Barra lateral Channel Page: Página do canal - Watch Page: Página de assistidos + Watch Page: Página de reprodução General: Geral Subscriptions Page: Página de inscrições Hide Featured Channels: Ocultar canais em destaque @@ -625,7 +622,7 @@ Settings: Show Family Friendly Only: Mostrar apenas conteúdo adequado para toda a família Hide Search Bar: Ocultar barra de pesquisa Parental Control Settings: Configurações de Controle Parental - Hide Unsubscribe Button: Ocultar botão de cancelamento de inscrição + Hide Unsubscribe Button: Ocultar botão "Cancelar inscrição" Experimental Settings: Experimental Settings: Configurações experimentais Warning: Essas configurações são experimentais, elas podem causar travamentos @@ -685,13 +682,13 @@ About: Licensed under the AGPLv3: Licença AGPLv3 Source code: Código-fonte Beta: Beta - Donate: Doar + Donate: Fazer doação these people and projects: estas pessoas e projetos FreeTube is made possible by: O FreeTube é possível graças a Credits: Créditos Translate: Traduzir room rules: regras da sala - Please read the: Por favor, leia o + Please read the: Por favor leia as Chat on Matrix: Bate-papo na Matrix Mastodon: Mastodon Email: E-mail @@ -1013,7 +1010,7 @@ Profile: Delete Profile: Excluir perfil Update Profile: Atualizar perfil Profile Preview: Pré-visualização do perfil - Color Picker: Seletor de cores + Color Picker: Escolha uma cor Create New Profile: Criar novo perfil All Channels: Todos os canais All subscriptions will also be deleted.: Todas as inscrições serão também excluídas. @@ -1025,7 +1022,7 @@ Profile: Custom Color: Cor personalizada Edit Profile: Editar perfil Profile Manager: Gerenciador de perfis - Profile Select: Seleção de perfil + Profile Select: Escolha um perfil Are you sure you want to delete the selected channels? This will not delete the channel from any other profile.: Tem certeza de que deseja excluir os canais selecionados? Isso não excluirá o canal de nenhum outro perfil. @@ -1115,10 +1112,6 @@ Tooltips: External Link Handling: "Escolha o comportamento padrão quando um link que não pode ser aberto no FreeTube for clicado.\nPor padrão, o FreeTube abrirá o link clicado em seu navegador padrão.\n" - Privacy Settings: - Remove Video Meta Files: Quando ativado, o FreeTube exclui automaticamente os - metarquivos criados durante a reprodução do vídeo quando a página de exibição - é fechada. External Player Settings: Custom External Player Arguments: Quaisquer argumentos de linha de comando personalizados, separados por ponto e vírgula (';'), você deseja que seja passado para o player @@ -1216,3 +1209,5 @@ Close Banner: Fechar Banner Age Restricted: This channel is age restricted: Este canal tem restrição de idade This video is age restricted: Este vídeo tem restrição de idade +checkmark: ✓ +Display Label: '{label}: {value}' diff --git a/static/locales/pt-PT.yaml b/static/locales/pt-PT.yaml index 679ca1b77..1d91532b3 100644 --- a/static/locales/pt-PT.yaml +++ b/static/locales/pt-PT.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: Português (PT) -FreeTube: FreeTube # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Esta parte da aplicação ainda não está pronta. Volte mais tarde quando já houver @@ -401,8 +400,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: Tem a certeza de que pretende remover todas as suas subscrições e perfis? Esta ação não pode ser revertida. - Automatically Remove Video Meta Files: Remover automaticamente os meta-ficheiros - dos vídeos Save Watched Videos With Last Viewed Playlist: Guardar os vídeos vistos com a última lista de reprodução vista Remove All Playlists: Remover todas as listas de reprodução @@ -1004,9 +1001,6 @@ Tooltips: # Toast Messages Fetch Automatically: Se ativa, FreeTube irá obter automaticamente as subscrições ao abrir uma nova janela e/ou quando mudar de perfil. - Privacy Settings: - Remove Video Meta Files: Se ativa, ao fechar uma página, FreeTube apagará automaticamente - os meta-ficheiros criados durante a reprodução de um vídeo. External Player Settings: Custom External Player Arguments: Quaisquer argumentos de linha de comando, separados por ponto e vírgula (';'), que quiser passar ao reprodutor externo. diff --git a/static/locales/pt.yaml b/static/locales/pt.yaml index e2819e7c6..f4c961846 100644 --- a/static/locales/pt.yaml +++ b/static/locales/pt.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Português' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Esta parte da aplicação ainda não está pronta. Volte mais tarde quando já houver @@ -128,7 +127,7 @@ User Playlists: Playlist Message: Esta página não é indicativa do resultado final. Apenas mostra os vídeos que foram guardados ou marcados como favoritos. Quando estiver pronta, todos os vídeos que estiverem aqui serão postos numa lista chamada 'Favoritos'. - Search bar placeholder: Procurar na lista de reprodução + Search bar placeholder: Procurar listas de reprodução Empty Search Message: Não há vídeos nesta lista de reprodução que coincidam com a sua pesquisa This playlist currently has no videos.: Esta lista de reprodução não tem vídeos @@ -196,6 +195,7 @@ User Playlists: qual adicionar o seu vídeo | Selecione uma lista de reprodução à qual adicionar os seus {videoCount} vídeos N playlists selected: '{playlistCount} selecionadas' + Added {count} Times: Adicionada {count} vez | Adicionada {count} vezes CreatePlaylistPrompt: New Playlist Name: Novo nome da lista de reprodução Create: Criar @@ -221,6 +221,7 @@ User Playlists: Enable Quick Bookmark With This Playlist: Ativar marcador rápido para esta lista de reprodução Disable Quick Bookmark: Desativar marcador rápido + Playlists with Matching Videos: Listas de reprodução coincidentes History: # On History Page History: 'Histórico' @@ -409,8 +410,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Tem a certeza de que pretende remover todas as suas subscrições e perfis? Esta ação não pode ser revertida.' - Automatically Remove Video Meta Files: Remover automaticamente os meta-ficheiros - dos vídeos Save Watched Videos With Last Viewed Playlist: Guardar os vídeos vistos com a última lista de reprodução vista Remove All Playlists: Remover todas as listas de reprodução @@ -565,7 +564,7 @@ Settings: Hide Channels: Ocultar vídeos dos canais Hide Channels Placeholder: ID do canal Display Titles Without Excessive Capitalisation: Mostrar títulos sem maiúsculas - em excesso + ou pontuação em excesso Hide Featured Channels: Ocultar canais em destaque Hide Channel Playlists: Ocultar listas de reprodução dos canais Hide Channel Community: Ocultar canal Comunidade @@ -1071,9 +1070,6 @@ This video is unavailable because of missing formats. This can happen due to cou vídeo não está disponível porque faltam formatos. Isto pode acontecer devido à indisponibilidade no seu país. Tooltips: - Privacy Settings: - Remove Video Meta Files: Se ativa, ao fechar uma página, FreeTube apagará automaticamente - os meta-ficheiros criados durante a reprodução de um vídeo. Subscription Settings: Fetch Feeds from RSS: Se ativa, FreeTube irá obter as subscrições através de RSS em vez do método normal. O formato RSS é mais rápido e não é bloqueado pelo @@ -1102,9 +1098,9 @@ Tooltips: vídeos em vez de fazer uma ligação direta ao YouTube. Ignora a preferência de API. Force Local Backend for Legacy Formats: Apenas funciona quando a API Invidious - é o seu sistema usado. Se ativa, a API local será executada para usar os formatos - antigos em vez dos usados pelo Invidious. Útil quando os vídeos do Invidious - não funcionam devido a restrições geográficas. + é sistema usado. Se ativa, a API local será executada para usar os formatos + antigos em vez dos usados pelo Invidious. Útil quando os vídeos Invidious não + funcionam devido a restrições geográficas. Scroll Playback Rate Over Video Player: Com o cursor sobre o vídeo, prima e mantenha premida a tecla Ctrl (Comando em Mac) e desloque a roda do rato para controlar a taxa de reprodução. Prima e mantenha premida a tecla Ctrl (Comando em Mac) @@ -1190,3 +1186,6 @@ Go to page: Ir para {page} Channel Unhidden: '{channel} removido do filtro do canal' Tag already exists: '"{tagName}" já existe' Close Banner: Fechar banner +Age Restricted: + This channel is age restricted: Este canal tem restrições de idade + This video is age restricted: Este vídeo tem restrições de idade diff --git a/static/locales/ro.yaml b/static/locales/ro.yaml index 652aad2d9..555e78d9b 100644 --- a/static/locales/ro.yaml +++ b/static/locales/ro.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'română' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Această parte a aplicației nu este gata încă. Revino mai târziu pentru modificări. @@ -51,7 +50,7 @@ A new blog is now available, {blogTitle}. Click to view more: 'Un nou blog este disponibil, {blogTitle}. Click to view more' # Search Bar -Search / Go to URL: 'Căutare / Întrodu la URL' +Search / Go to URL: 'Căutare / Accesați URL-ul' # In Filter Button Search Filters: Search Filters: 'Filtre de căutare' @@ -130,8 +129,48 @@ User Playlists: Aceasta enumeră doar videoclipurile pe care le-ați salvat sau le-ați favorizat. Când lucrările vor fi finalizate, toate videoclipurile care se află în prezent aici vor fi migrate într-o listă de redare "Favorite". - Search bar placeholder: Caută în Listă De Redare + Search bar placeholder: Căutați liste de redare Empty Search Message: Nu sunt videoclipuri pentru căutarea ta + Move Video Down: Mutați video în jos + Enable Quick Bookmark With This Playlist: Activați marcajul rapid cu această listă + de redare + Sort By: + Sort By: Sortează după + NameDescending: Z-A + LatestCreatedFirst: Creat recent + NameAscending: A-Z + LatestUpdatedFirst: Actualizat recent + EarliestCreatedFirst: Cel mai devreme creat + This playlist currently has no videos.: Această listă de redare nu are în prezent + niciun videoclip. + You have no playlists. Click on the create new playlist button to create a new one.: Nu + aveți liste de redare. Faceți clic pe butonul de creare a unei noi liste de redare + pentru a crea una nouă. + Playlists with Matching Videos: Liste de redare cu videoclipuri corespunzătoare + AddVideoPrompt: + Select a playlist to add your N videos to: Selectați o listă de redare la care + să adăugați videoclipul dvs. | Selectați o listă de redare la care să adăugați + videoclipurile {videoCount} + Cancel: Anulare + Edit Playlist Info: Editați informațiile despre lista de redare + Copy Playlist: Copiați lista de redare + Remove Watched Videos: Eliminați videoclipurile vizionate + Are you sure you want to remove all watched videos from this playlist? This cannot be undone: Sunteți + sigur că doriți să eliminați toate videoclipurile vizionate din această listă + de redare? Acest lucru nu poate fi anulat. + Create New Playlist: Creați o nouă listă de redare + Add to Playlist: Adăugați la lista de redare + Add to Favorites: Adaugă la {playlistName} + Remove from Favorites: Eliminați din {playlistName} + Move Video Up: Mutați video în sus + Remove from Playlist: Eliminați din lista de redare + Playlist Name: Numele listei de redare + Playlist Description: Descrierea listei de redare + Save Changes: Salvați modificările + Disable Quick Bookmark: Dezactivați marcajul rapid + Delete Playlist: Ștergeți lista de redare + Are you sure you want to delete this playlist? This cannot be undone: Sunteți sigur + că doriți să ștergeți această listă de redare? Acest lucru nu poate fi anulat. History: # On History Page History: 'Istoric' @@ -317,7 +356,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Sunteți sigur că doriți să eliminați toate abonamentele și profilurile? Acest lucru nu poate fi anulat.' - Automatically Remove Video Meta Files: Îndepărtați automat fișierele meta video Save Watched Videos With Last Viewed Playlist: Salvați videoclipurile vizionate cu ultima listă de redare vizualizată Subscription Settings: @@ -407,8 +445,8 @@ Settings: Hide Live Streams: Ascunde stream-urile live Hide Sharing Actions: Ascunde butoanele de sharing Hide Chapters: Ascundeți capitolele - Display Titles Without Excessive Capitalisation: Afișați titluri fără majuscule - excesive + Display Titles Without Excessive Capitalisation: Afișați titlurile fără majuscule + și semne de punctuație excesive Sections: Subscriptions Page: Pagina de abonamente Side Bar: Bară laterală @@ -424,7 +462,7 @@ Settings: Hide Channel Community: Ascunde comunitatea canalului Hide Channel Shorts: Ascundeți canalul Shorts Hide Featured Channels: Ascundeți canalele recomandate - Hide Channels Placeholder: Numele canalului sau ID-ul + Hide Channels Placeholder: ID-ul canalului Hide Channel Playlists: Ascunde playlisturile canalului Hide Upcoming Premieres: Ascundeți premierele viitoare Blur Thumbnails: Estomparea miniaturilor @@ -893,9 +931,6 @@ Hashtags have not yet been implemented, try again later: Hashtag-urile nu au fos Unknown YouTube url type, cannot be opened in app: Tip url YouTube necunoscut, nu poate fi deschis în aplicație Tooltips: - Privacy Settings: - Remove Video Meta Files: Atunci când este activat, FreeTube șterge automat fișierele - meta create în timpul redării video, atunci când pagina de vizionare este închisă. Subscription Settings: Fetch Feeds from RSS: Atunci când este activată, FreeTube va utiliza RSS în locul metodei implicite pentru a prelua feed-ul de abonament. RSS este mai rapid și diff --git a/static/locales/ru.yaml b/static/locales/ru.yaml index f1cec0bf7..b5a31e62e 100644 --- a/static/locales/ru.yaml +++ b/static/locales/ru.yaml @@ -1,7 +1,6 @@ -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- - Эта часть приложения ещё не готова. Вернитесь позже, когда выйдет новая версия. + Эта часть приложения ещё не готова. Вернитесь позже, когда появится новая версия. # Webkit Menu Bar File: 'Файл' @@ -120,7 +119,7 @@ User Playlists: только те видео, которые вы сохранили или добавили в избранное. После переработки этой страницы все видео, которые сейчас находятся здесь, переместятся в подборку «Избранное». - Search bar placeholder: Поиск в подборке + Search bar placeholder: Поиск подборок Empty Search Message: В этой подборке нет видео, соответствующих вашему запросу This playlist currently has no videos.: Пока в этой подборке нет видео. Add to Playlist: Добавить в подборку @@ -162,6 +161,7 @@ User Playlists: This video cannot be moved up.: Это видео нельзя передвинуть вверх. This video cannot be moved down.: Это видео нельзя передвинуть вниз. Video has been removed: Видео было удалено + Search for Videos: Поиск видео AddVideoPrompt: N playlists selected: '{playlistCount} выбрано' Search in Playlists: Поиск подборок @@ -170,8 +170,8 @@ User Playlists: You haven't selected any playlist yet.: Ещё не выбрана ни одна подборка. "{videoCount} video(s) added to 1 playlist": 1 видео добавлено в 1 подборку | {videoCount} видео добавлено в 1 подборку - Select a playlist to add your N videos to: Выбери подборку на добавление твоего - видео | Выбери подборку на добавление твоих {videoCount} видео в неё + Select a playlist to add your N videos to: Выбери подборку на добавление видео + | Выбери подборку на добавление {videoCount} видео в неё CreatePlaylistPrompt: Toast: Playlist {playlistName} has been successfully created.: Подборка {playlistName} @@ -193,6 +193,8 @@ User Playlists: You have no playlists. Click on the create new playlist button to create a new one.: У тебя нет подборок. Нажми на кнопку создания новой подборки, чтобы создать новую. Create New Playlist: Создать новую подборку + Add to Favorites: Добавить в {playlistName} + Remove from Favorites: Убрать из {playlistName} History: # On History Page History: 'История' @@ -425,7 +427,6 @@ Settings: Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: Выполнить удаление всех подписок и учётных записей? Невозможно отменить. Remove All Subscriptions / Profiles: Удалить все подписки/профили - Automatically Remove Video Meta Files: Автоудаление метафайлов видео Save Watched Videos With Last Viewed Playlist: Сохранить просмотренные видео с последней просмотренной подборкой Are you sure you want to remove all your playlists?: Ты действительно хочешь удалить @@ -506,8 +507,8 @@ Settings: Hide Upcoming Premieres: Скрыть предстоящие премьеры Hide Channels Placeholder: Идентификатор канала Hide Channels: Скрыть видео с каналов - Display Titles Without Excessive Capitalisation: Отображать заголовки без чрезмерного - использования заглавных букв + Display Titles Without Excessive Capitalisation: Отображать заголовки без сплошных + заглавных букв и знаков препинания Hide Featured Channels: Скрыть избранные каналы Hide Channel Playlists: Скрыть подборки канала Hide Channel Community: Скрыть сообщество канала @@ -531,6 +532,10 @@ Settings: Hide Channels Already Exists: Идентификатор канала уже существует Hide Channels API Error: Ошибка при получении пользователя с предоставленным идентификатором. Пожалуйста, проверьте еще раз, правильно ли указан идентификатор. + Hide Videos and Playlists Containing Text: Скрыть видео и подборки, содержащие + текст + Hide Videos and Playlists Containing Text Placeholder: Слово, часть слова, или + выражение The app needs to restart for changes to take effect. Restart and apply change?: Чтобы изменения вступили в силу, необходимо перезапустить приложение. Перезапустить и применить изменения? @@ -564,6 +569,9 @@ Settings: Do Nothing: Ничего не делать Category Color: Цвет категории UseDeArrowTitles: Использовать заголовки видео «DeArrow» + UseDeArrowThumbnails: Использовать DeArrow для заставок + 'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': Адрес + набора функций (API) генератора заставок DeArrow (По умолчанию, это https://dearrow-thumb.ajay.app) External Player Settings: Custom External Player Arguments: Аргументы внешнего проигрывателя Custom External Player Executable: Исполняемый файл внешнего проигрывателя @@ -711,6 +719,7 @@ Channel: votes: 'Голосов: {votes}' Hide Answers: Скрыть ответы Reveal Answers: Раскрыть ответы + Video hidden by FreeTube: Видео скрыто FreeTube'ом Live: Live: Трансляции This channel does not currently have any live streams: На этом канале в настоящее @@ -870,6 +879,7 @@ Video: Pause on Current Video: Остановиться на текущем видео Hide Channel: Скрыть канал Unhide Channel: Показать канал + More Options: Больше настроек Videos: #& Sort By Sort By: @@ -1073,10 +1083,6 @@ Tooltips: H.264. Форматы DASH AV1 требуют большей производительности для воспроизведения! Они доступны не для всех видео. Если они будут недоступны, тогда проигрыватель будет использовать форматы DASH H.264. - Privacy Settings: - Remove Video Meta Files: Если эта настройка включена, FreeTube автоматически удаляет - метаданные, созданные во время воспроизведения видео, когда страница просмотра - закрывается. External Player Settings: Custom External Player Arguments: Любые пользовательские аргументы командной строки, разделенные точкой с запятой (';'), которые вы хотите передать внешнему проигрывателю. @@ -1101,9 +1107,14 @@ Tooltips: Введенный идентификатор канала должен полностью совпадать и чувствителен к регистру. Hide Subscriptions Live: Эта настройка переопределена общей настройкой «{appWideSetting}», в подразделе «{subsection}» раздела «{settingsSection}» + Hide Videos and Playlists Containing Text: 'Вставь слово, часть слова, или выражение + (вне зависимости от регистра), чтобы скрыть все видео и подборки, в чьих названиях + содержится что-либо вставленное сюда; за исключением только: истории, подборок + и видео в подборках.' SponsorBlock Settings: UseDeArrowTitles: Заменить пользовательски-размещённые заголовки на заголовки, предоставляемые «DeArrow». + UseDeArrowThumbnails: Заменить заставки видео, заставками от DeArrow. More: Больше Playing Next Video Interval: Воспроизведение следующего видео без задержки. Нажмите для отмены. | Воспроизведение следующего видео через {nextVideoInterval} сек. Нажмите @@ -1159,3 +1170,7 @@ Playlist will pause when current video is finished: Подборка остан видео закончится Channel Unhidden: '{channel} удалён из канального фильтровщика' Channel Hidden: '{channel} добавлен в канальный фильтровщик' +Age Restricted: + This channel is age restricted: Канал с возрастным ограничением + This video is age restricted: Видео с возрастным ограничением +Tag already exists: «{tagName}» метка уже существует diff --git a/static/locales/sat.yaml b/static/locales/sat.yaml index 22219df44..a8be0f7a5 100644 --- a/static/locales/sat.yaml +++ b/static/locales/sat.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'ᱥᱟᱱᱛᱟᱲᱤ' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- ᱮᱯᱯ ᱨᱮᱭᱟᱜ ᱱᱚᱶᱟ ᱡᱟᱭᱜᱟ ᱵᱟᱝ ᱛᱮᱭᱟᱨ ᱡᱩᱛ ᱠᱟᱱᱟ ᱾ ᱠᱟᱹᱢᱤ ᱪᱟᱵᱟ ᱠᱟᱛᱮ ᱦᱟᱹᱡᱩᱜᱽ ᱢᱮᱸ ᱾ diff --git a/static/locales/si.yaml b/static/locales/si.yaml index b2a4be309..c6edfc65b 100644 --- a/static/locales/si.yaml +++ b/static/locales/si.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'සිංහල' -FreeTube: 'ෆ්‍රීටියුබ්' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- යෙදුමේ මෙම කොටස තවම සූදානම් නැත. ප්‍රගතියක් ලබා ඇති පසු නැවත එන්න. diff --git a/static/locales/sk.yaml b/static/locales/sk.yaml index 1882ad076..3fc5c2e47 100644 --- a/static/locales/sk.yaml +++ b/static/locales/sk.yaml @@ -1,4 +1,3 @@ -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Táto časť aplikácie ešte nie je dokončená. Vráťte sa neskôr keď na nej spravíme @@ -329,7 +328,6 @@ Settings: Are you sure you want to remove your entire watch history?: Naozaj chcete odstrániť celú históriu pozerania? Search cache has been cleared: Vyrovnávacia pamäť vyhľadávania bola vymazaná - Automatically Remove Video Meta Files: Automaticky Odstrániť Metasúbory Videa The app needs to restart for changes to take effect. Restart and apply change?: Aplikácia požaduje reštart, aby sa zmeny prejavili. Reštartovať a aplikovať zmeny? Proxy Settings: @@ -701,9 +699,6 @@ Tooltips: External Link Handling: "Vyberte predvolené správanie pri kliknutí na odkaz, ktorý nemožno otvoriť vo FreeTube.\nV predvolenom nastavení FreeTube otvorí odkaz, na ktorý ste klikli, vo vašom predvolenom prehliadači.\n" - Privacy Settings: - Remove Video Meta Files: Ak je povolené, FreeTube po zatvorení stránky prezerania - automaticky odstráni metasúbory vytvorené počas prehrávania videa. External Player Settings: DefaultCustomArgumentsTemplate: "(Predvolené: '{defaultCustomArguments}')" External Player: Po výbere externého prehrávača sa na miniatúre zobrazí ikona diff --git a/static/locales/sl.yaml b/static/locales/sl.yaml index 01fbe4264..64416d0fa 100644 --- a/static/locales/sl.yaml +++ b/static/locales/sl.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'slovenščina' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Ta del programa še ni pripravljen za uporabo. Prosimo, pridite nazaj kasneje, ko @@ -297,7 +296,6 @@ Settings: mogoče razveljaviti.' Save Watched Videos With Last Viewed Playlist: Shrani gledane videoposnetke z nazadnje ogledanim seznamom predvajanja - Automatically Remove Video Meta Files: Samodejno izbriši meta datoteke videoposnetkov Subscription Settings: Subscription Settings: 'Nastavitve naročnin' Hide Videos on Watch: 'Skrij gledane videoposnetke' diff --git a/static/locales/sm.yaml b/static/locales/sm.yaml index e80aadef6..871440bfe 100644 --- a/static/locales/sm.yaml +++ b/static/locales/sm.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Gagana Samoa' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- E le saauni le vaega o le polokalama lenei. Fa'amolemole toe fo'i mai afea na fai @@ -308,7 +307,6 @@ Settings: Remember History: '' Save Watched Progress: '' Save Watched Videos With Last Viewed Playlist: '' - Automatically Remove Video Meta Files: '' Clear Search Cache: '' Are you sure you want to clear out your search cache?: '' Search cache has been cleared: '' @@ -803,8 +801,6 @@ Tooltips: Subscription Settings: Fetch Feeds from RSS: '' Fetch Automatically: '' - Privacy Settings: - Remove Video Meta Files: '' Experimental Settings: Replace HTTP Cache: '' SponsorBlock Settings: diff --git a/static/locales/sr.yaml b/static/locales/sr.yaml index 0004b8f0d..291aac79c 100644 --- a/static/locales/sr.yaml +++ b/static/locales/sr.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Српски' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Овај део апликације још није спреман. Вратите се касније када буде постигнут напредак. @@ -419,8 +418,6 @@ Settings: Remove All Subscriptions / Profiles: 'Уклони сва праћења/профиле' Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Желите ли заиста да уклоните сва праћења и профиле? Ово се не може поништити.' - Automatically Remove Video Meta Files: Аутоматски уклони мета фајлове за видео - снимак Save Watched Videos With Last Viewed Playlist: Сачувај одгледане видео снимке са последње гледане плејлисте All playlists have been removed: Све плејлисте су уклоњене @@ -940,9 +937,6 @@ Tooltips: разликује велика и мала слова) да бисте сакрили све видео снимке и плејлисте чији их оригинални наслови садрже у целом FreeTube-у, искључујући само историју, ваше плејлисте и видео снимке унутар плејлиста. - Privacy Settings: - Remove Video Meta Files: Када је омогућено, FreeTube аутоматски брише мета фајлове - направљене током репродукције видео снимка, када се страница гледања затвори. Player Settings: Allow DASH AV1 formats: DASH AV1 формати могу изгледати боље од DASH H.264 формата. DASH AV1 формати захтевају више снаге за репродукцију! Они нису доступни на @@ -1122,3 +1116,5 @@ Close Banner: Затвори банер Age Restricted: This channel is age restricted: Овај канал је ограничен према узрасту This video is age restricted: Овај видео снимак је ограничен према узрасту +Display Label: '{label}: {value}' +checkmark: ✓ diff --git a/static/locales/sv.yaml b/static/locales/sv.yaml index 1f8c8fac0..784b28a7c 100644 --- a/static/locales/sv.yaml +++ b/static/locales/sv.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Svenska' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Den här delen av appen är inte klar än. Kom tillbaka senare när framsteg har gjorts. @@ -331,7 +330,6 @@ Settings: Remove All Subscriptions / Profiles: 'Ta bort alla prenumerationer och profiler' Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Vill du verkligen ta bort alla prenumerationer och profiler? Detta kan inte ångras.' - Automatically Remove Video Meta Files: Ta automatiskt bort videons metafiler Save Watched Videos With Last Viewed Playlist: Spara sedda vidoer till Senast tittade spellista Subscription Settings: @@ -978,9 +976,6 @@ Tooltips: External Link Handling: "Välj standardförfarande när en länk klickas, som inte kan öppnas i FreeTube är. \nStandard är att FreeTube kommer öppna länken i din standardwebbläsare.\n" - Privacy Settings: - Remove Video Meta Files: Om vald, kommer FreeTube automatiskt att kasta metadata - filer som skapades under uppspelning, när sidan stängs. External Player Settings: Custom External Player Arguments: Alla anpassade kommandoradsargument, åtskilda av semikolon (';'), ska skickas till den externa spelaren. diff --git a/static/locales/ti.yaml b/static/locales/ti.yaml index 4de64898d..d45365585 100644 --- a/static/locales/ti.yaml +++ b/static/locales/ti.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'ትግርኛ' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- እዚ ኽፋል .app ምሉእ ኣይኰነን ። diff --git a/static/locales/tr.yaml b/static/locales/tr.yaml index 2f83cfcf7..0aea069ae 100644 --- a/static/locales/tr.yaml +++ b/static/locales/tr.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Türkçe' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Uygulamanın bu bölümü henüz hazır değil. Tamamlanınca geri gelin. @@ -412,8 +411,6 @@ Settings: Remove All Subscriptions / Profiles: 'Tüm Abonelikler/Profilleri Temizle' Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Tüm abonelikler/profilleri temizlemek istediğinizden emin misiniz? Geri alınamaz.' - Automatically Remove Video Meta Files: Video Meta Dosyalarını Otomatik Olarak - Kaldır Save Watched Videos With Last Viewed Playlist: İzlenen Videoları Son Görüntülenen Oynatma Listesiyle Kaydet All playlists have been removed: Tüm oynatma listeleri kaldırıldı @@ -1107,9 +1104,6 @@ Tooltips: External Link Handling: "FreeTube'da açılamayan bir bağlantı tıklandığında öntanımlı davranışı seçin.\nÖntanımlı olarak FreeTube, tıklanan bağlantıyı öntanımlı tarayıcınızda açacaktır.\n" - Privacy Settings: - Remove Video Meta Files: Etkinleştirildiğinde, izleme sayfası kapatıldığında video - oynatma sırasında oluşturulan meta dosyaları otomatik olarak silinir. External Player Settings: Custom External Player Arguments: Harici oynatıcıya iletmek isteyeceğiniz, noktalı virgülle (';') ayrılmış özel komut satırı argümanları. @@ -1214,3 +1208,5 @@ Close Banner: Afişi Kapat Age Restricted: This video is age restricted: Bu videoda yaş sınırlaması var This channel is age restricted: Bu kanalda yaş sınırlaması var +Display Label: '{label}: {value}' +checkmark: ✓ diff --git a/static/locales/uk.yaml b/static/locales/uk.yaml index a69e6c904..7c691b993 100644 --- a/static/locales/uk.yaml +++ b/static/locales/uk.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'Українська' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Ця частина застосунка ще не готова. Поверніться пізніше. @@ -341,7 +340,6 @@ Settings: Remove All Subscriptions / Profiles: 'Видалити всі підписки / профілі' Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 'Справді хочете вилучити всі підписки та профілі? Цю дію не можна скасувати.' - Automatically Remove Video Meta Files: Автоматично вилучати метафайли відео Save Watched Videos With Last Viewed Playlist: Зберегти переглянуті відео у список відтворення, який ви переглядали останнім часом Subscription Settings: @@ -922,9 +920,6 @@ Tooltips: # Toast Messages Fetch Automatically: Якщо увімкнено, FreeTube автоматично отримуватиме вашу стрічку підписок під час відкриття нового вікна та за перемикання профілю. - Privacy Settings: - Remove Video Meta Files: Якщо увімкнено, FreeTube автоматично видаляє метафайли, - створені під час відтворення відео, коли сторінку перегляду закрито. External Player Settings: Custom External Player Arguments: Будь-які нетипові аргументи командного рядка розділяються (';') крапкою з комою, ви бажаєте, щоб вас було перенаправлено diff --git a/static/locales/ur.yaml b/static/locales/ur.yaml index cd84b2405..0c4030bfd 100644 --- a/static/locales/ur.yaml +++ b/static/locales/ur.yaml @@ -1,6 +1,5 @@ # Put the name of your locale in the same language Locale Name: 'اردو' -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- 'ایپ کا یہ حصہ ابھی تک تیار نہیں ہے۔ جب پیش رفت ہو جائے تو بعد میں واپس آئیں۔' @@ -201,9 +200,6 @@ Tooltips: کرے گا۔ آپ کی سبسکرپشن فیڈ حاصل کرنے کا طریقہ۔ آر ایس ایس تیز ہے اور آئی پی کو بلاک کرنے سے روکتا ہے، لیکن کچھ معلومات فراہم نہیں کرتا ہے جیسے ویڈیو کا دورانیہ یا لائیو اسٹیٹس' - Privacy Settings: - Remove Video Meta Files: 'فعال ہونے پر، FreeTube ویڈیو پلے بیک کے دوران بنائی - گئی میٹا فائلوں کو خود بخود حذف کر دیتا ہے، جب دیکھنے کا صفحہ بند ہوتا ہے۔' # Toast Messages This video is unavailable because of missing formats. This can happen due to country unavailability.: 'یہ diff --git a/static/locales/vi.yaml b/static/locales/vi.yaml index b84a3936b..1ea7a3b42 100644 --- a/static/locales/vi.yaml +++ b/static/locales/vi.yaml @@ -1,5 +1,4 @@ Locale Name: Tiếng Việt -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- Phần này của app vẫn chưa sẵn sàng. Quay lại sau khi quá trình đã được thực hiện. @@ -542,7 +541,6 @@ Settings: Save Watched Progress: Lưu quá trình xem Remember History: Nhớ lịch sử Privacy Settings: Cài đặt quyền riêng tư - Automatically Remove Video Meta Files: Tự động xóa các tệp meta video Remove All Playlists: Xóa tất cả danh sách phát Are you sure you want to remove all your playlists?: Bạn có chắc muốn xóa tất cả các danh sách phát không? @@ -1112,9 +1110,6 @@ Tooltips: hoặc trạng thái phát trực tiếp Fetch Automatically: Khi được bật, FreeTube sẽ tự động tìm nạp nguồn cấp dữ liệu đăng ký của bạn khi cửa sổ mới được mở và khi chuyển đổi hồ sơ. - Privacy Settings: - Remove Video Meta Files: Khi được bật lên, FreeTube sẽ tự động xóa các tệp meta - được tạo trong quá trình phát lại video, khi trang xem bị đóng. Distraction Free Settings: Hide Channels: Nhập tên kênh hoặc ID kênh để ẩn tất cả video, danh sách phát và chính kênh đó khỏi xuất hiện trong tìm kiếm, xu hướng, phổ biến nhất và được diff --git a/static/locales/zh-CN.yaml b/static/locales/zh-CN.yaml index 52b2291b0..2e5be9357 100644 --- a/static/locales/zh-CN.yaml +++ b/static/locales/zh-CN.yaml @@ -1,4 +1,3 @@ -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- 应用此部分尚未完成。有了进展再来。 @@ -403,7 +402,6 @@ Settings: Clear Search Cache: 清除搜索缓存 Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 您确定您想移除所有订阅和配置文件吗?这无法撤销。 Remove All Subscriptions / Profiles: 移除所有订阅 / 配置文件 - Automatically Remove Video Meta Files: 自动删除硬盘元数据文件 Save Watched Videos With Last Viewed Playlist: 记住上次看过的播放列表中看过的视频 ID All playlists have been removed: 已删除所有播放列表 Remove All Playlists: 删除所有播放列表 @@ -979,8 +977,6 @@ Tooltips: DefaultCustomArgumentsTemplate: "(默认: '{defaultCustomArguments}')" Custom External Player Arguments: 任何你希望传递给外部播放器的用分号(';')分隔的自定义命令行参数。 Ignore Default Arguments: 不要向外部播放器发送除视频 URL 外的任何默认变量(如播放速度、播放列表 URL 等)。自定义变量仍将被传递。 - Privacy Settings: - Remove Video Meta Files: 启用后,当观看页面关闭时,FreeTube 会自动删除在视频播放时创建的元文件。 Experimental Settings: Replace HTTP Cache: 禁用 Electron 基于磁盘的 HTTP 缓存,启用自定义内存中图像缓存。会增加内存的使用。 Distraction Free Settings: @@ -1044,3 +1040,5 @@ Close Banner: 关闭横幅 Age Restricted: This video is age restricted: 此视频有年龄限制 This channel is age restricted: 此频道有年龄限制 +checkmark: ✓ +Display Label: '{label}: {value}' diff --git a/static/locales/zh-TW.yaml b/static/locales/zh-TW.yaml index daae2fb45..863a6f341 100644 --- a/static/locales/zh-TW.yaml +++ b/static/locales/zh-TW.yaml @@ -1,4 +1,3 @@ -FreeTube: 'FreeTube' # Currently on Subscriptions, Playlists, and History 'This part of the app is not ready yet. Come back later when progress has been made.': >- 此功能尚未製作完成。有更新再來喔。 @@ -405,7 +404,6 @@ Settings: Privacy Settings: 隱私設定 Are you sure you want to remove all subscriptions and profiles? This cannot be undone.: 您確定要移除所有訂閱與設定檔嗎嗎? 注意:這無法復原。 Remove All Subscriptions / Profiles: 移除所有訂閱/設定檔 - Automatically Remove Video Meta Files: 自動刪除影片元檔案 Save Watched Videos With Last Viewed Playlist: 使用上次觀看的播放清單儲存觀看的影片 Remove All Playlists: 移除所有播放清單 All playlists have been removed: 所有播放清單已被移除 @@ -983,8 +981,6 @@ Tooltips: API 需要 Invidious 伺服器才能連線。 Region for Trending: 熱門影片區域可以讓您選擇想要顯示哪個國家的熱門影片。 External Link Handling: "選擇點擊後無法在 FreeTube 中開啟連結時的預設行為。\n預設情況下 FreeTube 將會在您的預設瀏覽器中開啟點擊的連結。\n" - Privacy Settings: - Remove Video Meta Files: 如果啟用,FreeTube會在關閉觀看頁面時,自動刪除影片播放過程中建立的暫存檔案。 External Player Settings: Custom External Player Arguments: 任何您想要傳遞給外部播放程式的自訂命令列參數,以半形冒號分隔 (';')。 Ignore Warnings: 當目前的外部播放程式不支援目前動作時(例如反向播放清單等等),消除警告。 @@ -1054,3 +1050,5 @@ Close Banner: 關閉橫幅 Age Restricted: This channel is age restricted: 此頻道有年齡限制 This video is age restricted: 此影片有年齡限制 +checkmark: ✓ +Display Label: '{label}:{value}' diff --git a/yarn.lock b/yarn.lock index 70ca3ff53..37d3da3c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -28,23 +28,23 @@ "@babel/highlight" "^7.24.2" picocolors "^1.0.0" -"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.23.5", "@babel/compat-data@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.1.tgz#31c1f66435f2a9c329bb5716a6d6186c516c3742" - integrity sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA== +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.23.5", "@babel/compat-data@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.4.tgz#6f102372e9094f25d908ca0d34fc74c74606059a" + integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== -"@babel/core@^7.24.3": - version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.3.tgz#568864247ea10fbd4eff04dda1e05f9e2ea985c3" - integrity sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ== +"@babel/core@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.4.tgz#1f758428e88e0d8c563874741bc4ffc4f71a4717" + integrity sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg== dependencies: "@ampproject/remapping" "^2.2.0" "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.1" + "@babel/generator" "^7.24.4" "@babel/helper-compilation-targets" "^7.23.6" "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.24.1" - "@babel/parser" "^7.24.1" + "@babel/helpers" "^7.24.4" + "@babel/parser" "^7.24.4" "@babel/template" "^7.24.0" "@babel/traverse" "^7.24.1" "@babel/types" "^7.24.0" @@ -63,10 +63,10 @@ eslint-visitor-keys "^2.1.0" semver "^6.3.1" -"@babel/generator@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.1.tgz#e67e06f68568a4ebf194d1c6014235344f0476d0" - integrity sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A== +"@babel/generator@^7.24.1", "@babel/generator@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.4.tgz#1fc55532b88adf952025d5d2d1e71f946cb1c498" + integrity sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw== dependencies: "@babel/types" "^7.24.0" "@jridgewell/gen-mapping" "^0.3.5" @@ -133,6 +133,21 @@ "@babel/helper-split-export-declaration" "^7.22.6" semver "^6.3.1" +"@babel/helper-create-class-features-plugin@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz#c806f73788a6800a5cfbbc04d2df7ee4d927cce3" + integrity sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-member-expression-to-functions" "^7.23.0" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-replace-supers" "^7.24.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + semver "^6.3.1" + "@babel/helper-create-regexp-features-plugin@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz#3e35f4e04acbbf25f1b3534a657610a000543d3c" @@ -350,10 +365,10 @@ "@babel/template" "^7.22.15" "@babel/types" "^7.22.19" -"@babel/helpers@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.1.tgz#183e44714b9eba36c3038e442516587b1e0a1a94" - integrity sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg== +"@babel/helpers@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.4.tgz#dc00907fd0d95da74563c142ef4cd21f2cb856b6" + integrity sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw== dependencies: "@babel/template" "^7.24.0" "@babel/traverse" "^7.24.1" @@ -369,10 +384,18 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.23.5", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.1.tgz#1e416d3627393fab1cb5b0f2f1796a100ae9133a" - integrity sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg== +"@babel/parser@^7.23.5", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1", "@babel/parser@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88" + integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== + +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz#6125f0158543fb4edf1c22f322f3db67f21cb3e1" + integrity sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.24.1": version "7.24.1" @@ -571,10 +594,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-block-scoping@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.1.tgz#27af183d7f6dad890531256c7a45019df768ac1f" - integrity sha512-h71T2QQvDgM2SmT29UYU6ozjMlAt7s7CSs5Hvy8f8cf/GM/Z4a2zMfN+fjVGaieeCrXR3EdQl6C4gQG+OgmbKw== +"@babel/plugin-transform-block-scoping@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz#28f5c010b66fbb8ccdeef853bef1935c434d7012" + integrity sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g== dependencies: "@babel/helper-plugin-utils" "^7.24.0" @@ -586,12 +609,12 @@ "@babel/helper-create-class-features-plugin" "^7.24.1" "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-transform-class-static-block@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.1.tgz#4e37efcca1d9f2fcb908d1bae8b56b4b6e9e1cb6" - integrity sha512-FUHlKCn6J3ERiu8Dv+4eoz7w8+kFLSyeVG4vDAikwADGjUCoHw/JHokyGtr8OR4UjpwPVivyF+h8Q5iv/JmrtA== +"@babel/plugin-transform-class-static-block@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz#1a4653c0cf8ac46441ec406dece6e9bc590356a4" + integrity sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg== dependencies: - "@babel/helper-create-class-features-plugin" "^7.24.1" + "@babel/helper-create-class-features-plugin" "^7.24.4" "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-class-static-block" "^7.14.5" @@ -925,15 +948,16 @@ "@babel/helper-create-regexp-features-plugin" "^7.22.15" "@babel/helper-plugin-utils" "^7.24.0" -"@babel/preset-env@^7.24.3": - version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.24.3.tgz#f3f138c844ffeeac372597b29c51b5259e8323a3" - integrity sha512-fSk430k5c2ff8536JcPvPWK4tZDwehWLGlBp0wrsBUjZVdeQV6lePbwKWZaZfK2vnh/1kQX1PzAJWsnBmVgGJA== +"@babel/preset-env@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.24.4.tgz#46dbbcd608771373b88f956ffb67d471dce0d23b" + integrity sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A== dependencies: - "@babel/compat-data" "^7.24.1" + "@babel/compat-data" "^7.24.4" "@babel/helper-compilation-targets" "^7.23.6" "@babel/helper-plugin-utils" "^7.24.0" "@babel/helper-validator-option" "^7.23.5" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.24.4" "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.24.1" "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.24.1" "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.24.1" @@ -960,9 +984,9 @@ "@babel/plugin-transform-async-generator-functions" "^7.24.3" "@babel/plugin-transform-async-to-generator" "^7.24.1" "@babel/plugin-transform-block-scoped-functions" "^7.24.1" - "@babel/plugin-transform-block-scoping" "^7.24.1" + "@babel/plugin-transform-block-scoping" "^7.24.4" "@babel/plugin-transform-class-properties" "^7.24.1" - "@babel/plugin-transform-class-static-block" "^7.24.1" + "@babel/plugin-transform-class-static-block" "^7.24.4" "@babel/plugin-transform-classes" "^7.24.1" "@babel/plugin-transform-computed-properties" "^7.24.1" "@babel/plugin-transform-destructuring" "^7.24.1" @@ -1032,6 +1056,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.14.0": + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.0.tgz#584c450063ffda59697021430cb47101b085951e" + integrity sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.18.6", "@babel/template@^7.22.15", "@babel/template@^7.22.5", "@babel/template@^7.24.0": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" @@ -1182,6 +1213,21 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== +"@eslint/eslintrc@^1.2.0": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e" + integrity sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.4.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + "@eslint/eslintrc@^2.1.4": version "2.1.4" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" @@ -1207,31 +1253,31 @@ resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.0.0.tgz#f22824caff3ae506b18207bad4126dbc6ccdb6b8" integrity sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ== -"@fortawesome/fontawesome-common-types@6.5.1": - version "6.5.1" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz#fdb1ec4952b689f5f7aa0bffe46180bb35490032" - integrity sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A== +"@fortawesome/fontawesome-common-types@6.5.2": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.2.tgz#eaf2f5699f73cef198454ebc0c414e3688898179" + integrity sha512-gBxPg3aVO6J0kpfHNILc+NMhXnqHumFxOmjYCFfOiLZfwhnnfhtsdA2hfJlDnj+8PjAs6kKQPenOTKj3Rf7zHw== -"@fortawesome/fontawesome-svg-core@^6.5.1": - version "6.5.1" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz#9d56d46bddad78a7ebb2043a97957039fcebcf0a" - integrity sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ== +"@fortawesome/fontawesome-svg-core@^6.5.2": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.2.tgz#4b42de71e196039b0d5ccf88559b8044e3296c21" + integrity sha512-5CdaCBGl8Rh9ohNdxeeTMxIj8oc3KNBgIeLMvJosBMdslK/UnEB8rzyDRrbKdL1kDweqBPo4GT9wvnakHWucZw== dependencies: - "@fortawesome/fontawesome-common-types" "6.5.1" + "@fortawesome/fontawesome-common-types" "6.5.2" -"@fortawesome/free-brands-svg-icons@^6.5.1": - version "6.5.1" - resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.5.1.tgz#e948cc02404277cb8ad40fe3573ca75f2830e876" - integrity sha512-093l7DAkx0aEtBq66Sf19MgoZewv1zeY9/4C7vSKPO4qMwEsW/2VYTUTpBtLwfb9T2R73tXaRDPmE4UqLCYHfg== +"@fortawesome/free-brands-svg-icons@^6.5.2": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.5.2.tgz#bfca0cebd2c4713dc93244e1fa8b384f1f023587" + integrity sha512-zi5FNYdmKLnEc0jc0uuHH17kz/hfYTg4Uei0wMGzcoCL/4d3WM3u1VMc0iGGa31HuhV5i7ZK8ZlTCQrHqRHSGQ== dependencies: - "@fortawesome/fontawesome-common-types" "6.5.1" + "@fortawesome/fontawesome-common-types" "6.5.2" -"@fortawesome/free-solid-svg-icons@^6.5.1": - version "6.5.1" - resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz#737b8d787debe88b400ab7528f47be333031274a" - integrity sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ== +"@fortawesome/free-solid-svg-icons@^6.5.2": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.2.tgz#9b40b077b27400a5e9fcbf2d15b986c7be69e9ca" + integrity sha512-QWFZYXFE7O1Gr1dTIp+D6UcFUF0qElOnZptpi7PBUMylJh+vFmIedVe1Ir6RM1t2tEQLLSV1k7bR4o92M+uqlw== dependencies: - "@fortawesome/fontawesome-common-types" "6.5.1" + "@fortawesome/fontawesome-common-types" "6.5.2" "@fortawesome/vue-fontawesome@^2.0.10": version "2.0.10" @@ -1257,6 +1303,48 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== +"@intlify/core-base@^9.1.9": + version "9.10.1" + resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-9.10.1.tgz#e61d507d35beb0c69f9c94566313f9520c25a84a" + integrity sha512-0+Wtjj04GIyglh5KKiNjRwgjpHrhqqGZhaKY/QVjjogWKZq5WHROrTi84pNVsRN18QynyPmjtsVUWqFKPQ45xQ== + dependencies: + "@intlify/message-compiler" "9.10.1" + "@intlify/shared" "9.10.1" + +"@intlify/eslint-plugin-vue-i18n@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@intlify/eslint-plugin-vue-i18n/-/eslint-plugin-vue-i18n-2.0.0.tgz#7308327452742c07e4aef8735f6a4b17cefd58f5" + integrity sha512-ECBD0TvQNa56XKyuM6FPIGAAl7MP6ODcgjBQJrzucNxcTb8fYTWmZ+xgBuvmvAtA0iE0D4Wp18UMild2N0bGyw== + dependencies: + "@eslint/eslintrc" "^1.2.0" + "@intlify/core-base" "^9.1.9" + "@intlify/message-compiler" "^9.1.9" + debug "^4.3.1" + glob "^8.0.0" + ignore "^5.0.5" + is-language-code "^3.1.0" + js-yaml "^4.0.0" + json5 "^2.1.3" + jsonc-eslint-parser "^2.0.0" + lodash "^4.17.11" + parse5 "^7.0.0" + semver "^7.3.4" + vue-eslint-parser "^9.0.0" + yaml-eslint-parser "^1.0.0" + +"@intlify/message-compiler@9.10.1", "@intlify/message-compiler@^9.1.9": + version "9.10.1" + resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.10.1.tgz#d70c9ec211dab67d50a42ad1fb782c0e02f89c42" + integrity sha512-b68UTmRhgZfswJZI7VAgW6BXZK5JOpoi5swMLGr4j6ss2XbFY13kiw+Hu+xYAfulMPSapcHzdWHnq21VGnMCnA== + dependencies: + "@intlify/shared" "9.10.1" + source-map-js "^1.0.2" + +"@intlify/shared@9.10.1": + version "9.10.1" + resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.10.1.tgz#024ad6dd4ee9581962437570b3dc25516c82f4e9" + integrity sha512-liyH3UMoglHBUn70iCYcy9CQlInx/lp50W2aeSxqqrvmG+LDj/Jj7tBJhBoQL4fECkldGhbmW0g2ommHfL6Wmw== + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" @@ -2393,21 +2481,21 @@ bluebird@^3.1.1, bluebird@^3.5.5: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -body-parser@1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.0.tgz#3de69bd89011c11573d7bfee6a64f11b6bd27cc5" - integrity sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg== +body-parser@1.20.2: + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== dependencies: bytes "3.1.2" - content-type "~1.0.4" + content-type "~1.0.5" debug "2.6.9" depd "2.0.0" destroy "1.2.0" http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.10.3" - raw-body "2.5.1" + qs "6.11.0" + raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" @@ -2882,6 +2970,11 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== +content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" @@ -2892,10 +2985,10 @@ cookie-signature@1.0.6: resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= -cookie@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== copy-webpack-plugin@^12.0.2: version "12.0.2" @@ -2973,16 +3066,16 @@ css-functions-list@^3.2.1: resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.2.1.tgz#2eb205d8ce9f9ce74c5c1d7490b66b77c45ce3ea" integrity sha512-Nj5YcaGgBtuUmn1D7oHqPW0c9iui7xsTsj5lIX8ZgevdfhmjFfKB3r8moHJtNJnctnYXJyYX5I1pp90HM4TPgQ== -css-loader@^6.10.0: - version "6.10.0" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.10.0.tgz#7c172b270ec7b833951b52c348861206b184a4b7" - integrity sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw== +css-loader@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-7.0.0.tgz#3456a621ce51f9dfd12b9674bfc7527c5e1821db" + integrity sha512-WrO4FVoamxt5zY9CauZjoJgXRi/LZKIk+Ta7YvpSGr5r/eMYPNp5/T9ODlMe4/1rF5DYlycG1avhV4g3A/tiAw== dependencies: icss-utils "^5.1.0" postcss "^8.4.33" - postcss-modules-extract-imports "^3.0.0" - postcss-modules-local-by-default "^4.0.4" - postcss-modules-scope "^3.1.1" + postcss-modules-extract-imports "^3.1.0" + postcss-modules-local-by-default "^4.0.5" + postcss-modules-scope "^3.2.0" postcss-modules-values "^4.0.0" postcss-value-parser "^4.2.0" semver "^7.5.4" @@ -3487,10 +3580,10 @@ electron-to-chromium@^1.4.668: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.715.tgz#bb16bcf2a3537962fccfa746b5c98c5f7404ff46" integrity sha512-XzWNH4ZSa9BwVUQSDorPWAUQ5WGuYz7zJUNpNif40zFCiCl20t8zgylmreNmn26h5kiyw2lg7RfTmeMBsDklqg== -electron@^29.1.5: - version "29.1.5" - resolved "https://registry.yarnpkg.com/electron/-/electron-29.1.5.tgz#b745b4d201c1ac9f84d6aa034126288dde34d5a1" - integrity sha512-1uWGRw/ffA62lcrklxGUgVxVtOHojsg/nwsYr+/F9cVjipZJn8iPv/ABGIIexhmUqWcho8BqfTJ4osCBa29gBg== +electron@^29.2.0: + version "29.2.0" + resolved "https://registry.yarnpkg.com/electron/-/electron-29.2.0.tgz#98e9d45dcebda124fb0bd1ff20fc509ec692101c" + integrity sha512-ALKrCN52RG4g9prx4DriXSPnY5WoiyRUCNp7zEVQuoiNOpHTNqMMpRidQAHzntV4hajF1LMWHVoBkwqIs1jHhg== dependencies: "@electron/get" "^2.0.0" "@types/node" "^20.9.0" @@ -3546,6 +3639,11 @@ entities@^4.2.0: resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174" integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA== +entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + env-paths@^2.2.0, env-paths@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" @@ -3867,12 +3965,13 @@ eslint-plugin-unicorn@^51.0.1: semver "^7.5.4" strip-indent "^3.0.0" -eslint-plugin-vue@^9.23.0: - version "9.23.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.23.0.tgz#1354a33b0cd21e0cb373557ff73c5d7a6698fbcd" - integrity sha512-Bqd/b7hGYGrlV+wP/g77tjyFmp81lh5TMw0be9093X02SyelxRRfCI6/IsGq/J7Um0YwB9s0Ry0wlFyjPdmtUw== +eslint-plugin-vue@^9.24.0: + version "9.24.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.24.0.tgz#71209f4652ee767f18c0bf56f25991b7cdc5aa46" + integrity sha512-9SkJMvF8NGMT9aQCwFc5rj8Wo1XWSMSHk36i7ZwdI614BU7sIOR28ZjuFPKp8YGymZN12BSEbiSwa7qikp+PBw== dependencies: "@eslint-community/eslint-utils" "^4.4.0" + globals "^13.24.0" natural-compare "^1.4.0" nth-check "^2.1.1" postcss-selector-parser "^6.0.15" @@ -3970,7 +4069,7 @@ eslint@^8.57.0: strip-ansi "^6.0.1" text-table "^0.2.0" -espree@^9.0.0, espree@^9.3.1, espree@^9.6.0, espree@^9.6.1: +espree@^9.0.0, espree@^9.3.1, espree@^9.4.0, espree@^9.6.0, espree@^9.6.1: version "9.6.1" resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== @@ -4054,16 +4153,16 @@ execa@^7.1.1: strip-final-newline "^3.0.0" express@^4.17.3: - version "4.18.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.1.tgz#7797de8b9c72c857b9cd0e14a5eea80666267caf" - integrity sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q== + version "4.19.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" + integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.0" + body-parser "1.20.2" content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.5.0" + cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" @@ -4079,7 +4178,7 @@ express@^4.17.3: parseurl "~1.3.3" path-to-regexp "0.1.7" proxy-addr "~2.0.7" - qs "6.10.3" + qs "6.11.0" range-parser "~1.2.1" safe-buffer "5.2.1" send "0.18.0" @@ -4545,6 +4644,17 @@ glob@^7.1.3, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + global-agent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/global-agent/-/global-agent-3.0.0.tgz#ae7cd31bd3583b93c5a16437a1afe27cc33a1ab6" @@ -4942,7 +5052,7 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^5.2.0, ignore@^5.2.4, ignore@^5.3.1: +ignore@^5.0.5, ignore@^5.2.0, ignore@^5.2.4, ignore@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== @@ -5181,6 +5291,13 @@ is-inside-container@^1.0.0: dependencies: is-docker "^3.0.0" +is-language-code@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-language-code/-/is-language-code-3.1.0.tgz#b2386b49227e7010636f16d0c2c681ca40136ab5" + integrity sha512-zJdQ3QTeLye+iphMeK3wks+vXSRFKh68/Pnlw7aOfApFSEIOhYa8P9vwwa6QrImNNBMJTiL1PpYF0f4BxDuEgA== + dependencies: + "@babel/runtime" "^7.14.0" + is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" @@ -5421,7 +5538,7 @@ js-tokens@^4.0.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^4.1.0: +js-yaml@^4.0.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -5502,11 +5619,21 @@ json5@^1.0.1, json5@^1.0.2: dependencies: minimist "^1.2.0" -json5@^2.2.0, json5@^2.2.3: +json5@^2.1.3, json5@^2.2.0, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +jsonc-eslint-parser@^2.0.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonc-eslint-parser/-/jsonc-eslint-parser-2.4.0.tgz#74ded53f9d716e8d0671bd167bf5391f452d5461" + integrity sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg== + dependencies: + acorn "^8.5.0" + eslint-visitor-keys "^3.0.0" + espree "^9.0.0" + semver "^7.3.5" + jsonc-eslint-parser@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/jsonc-eslint-parser/-/jsonc-eslint-parser-2.1.0.tgz#4c126b530aa583d85308d0b3041ff81ce402bbb2" @@ -5590,59 +5717,59 @@ lazy-val@^1.0.4, lazy-val@^1.0.5: resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.5.tgz#6cf3b9f5bc31cee7ee3e369c0832b7583dcd923d" integrity sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q== -lefthook-darwin-arm64@1.6.7: - version "1.6.7" - resolved "https://registry.yarnpkg.com/lefthook-darwin-arm64/-/lefthook-darwin-arm64-1.6.7.tgz#24fd8600a483e6d88ff504ad6097ac9146b74552" - integrity sha512-/Li1ssZd8WYpBMq2Aqs7AZGWtKpJQJkWkfrEzT6ke7gjNngBurRkVJcEpoiRJpzhk6J+HZTk3Pimh8XaYI0KHw== +lefthook-darwin-arm64@1.6.8: + version "1.6.8" + resolved "https://registry.yarnpkg.com/lefthook-darwin-arm64/-/lefthook-darwin-arm64-1.6.8.tgz#ce7225a8589fb17f1ec130cb7097b26e2cd2b40a" + integrity sha512-L7iZVANp92MsYHRlpOlItXWGS6QL0w1E6T5GO00SGVoVPClA+Tkt26BFPhLZKa3pMbSHEhGTHeBMWJZ2Un/TnQ== -lefthook-darwin-x64@1.6.7: - version "1.6.7" - resolved "https://registry.yarnpkg.com/lefthook-darwin-x64/-/lefthook-darwin-x64-1.6.7.tgz#a4a7cf916e1e251026dcb8644155d1e65d5fb8cb" - integrity sha512-ZKRUFea0j/pco3NoypOHlzmSaYx5UYq47qywiqMUDmXz/38sjRlt8apKSNS3rlsPyPw+9g1c+pWwi+mQiHOnDg== +lefthook-darwin-x64@1.6.8: + version "1.6.8" + resolved "https://registry.yarnpkg.com/lefthook-darwin-x64/-/lefthook-darwin-x64-1.6.8.tgz#534cc97c0eaa1febca9fb5be6e6793da5d10a20f" + integrity sha512-BhYwl1CBi0eKKfsD9Bd6a6wmmaLHaZEBS5PlGc0h8hRWxC+CmBZyR0VDqXli9yxmgraI6psehM+w1v7RkP5pSg== -lefthook-freebsd-arm64@1.6.7: - version "1.6.7" - resolved "https://registry.yarnpkg.com/lefthook-freebsd-arm64/-/lefthook-freebsd-arm64-1.6.7.tgz#89417428f50ff6eaa5114356758b6a9605442b35" - integrity sha512-kY1/+SqxGg4xyKCXOZG9tSmBSHr1m7IoGy4G4FlbmLcZeq4n1JUlhPz/05rbIemR7HXOwA5CAGyjooxT4hNfyw== +lefthook-freebsd-arm64@1.6.8: + version "1.6.8" + resolved "https://registry.yarnpkg.com/lefthook-freebsd-arm64/-/lefthook-freebsd-arm64-1.6.8.tgz#bd32db03d72fb4df197c93e2759d4ef9a902255a" + integrity sha512-pr86NVKUOiK0MwW2UZRLiDlYLV8XaqxKWRltVut4W78Ywb0PNTb3k4LVeMwfXiNqEgD8gug9vE8aZY1U3D2HMA== -lefthook-freebsd-x64@1.6.7: - version "1.6.7" - resolved "https://registry.yarnpkg.com/lefthook-freebsd-x64/-/lefthook-freebsd-x64-1.6.7.tgz#9fd69a1d7b4b9622c01f6ccbb9e2db9a510c07c6" - integrity sha512-rC9/G6WPKWyxNB68HsUxngOdcTAHTux04LgDgC0j6OOFgpo8cEYHSNTHv4ERz79FxCPBmNe4Cg+mIXHYg8b8RQ== +lefthook-freebsd-x64@1.6.8: + version "1.6.8" + resolved "https://registry.yarnpkg.com/lefthook-freebsd-x64/-/lefthook-freebsd-x64-1.6.8.tgz#171c1c829cde0f7f27943cb483254b078b50b632" + integrity sha512-pyzYRCHf6jSWoZJG22kE7KFbHQ1B6sHcxXP9o/Y5H8T/sHUxO03GEtdrGwyijMP0EJYb1vMfVWYY5WbWfg6SPg== -lefthook-linux-arm64@1.6.7: - version "1.6.7" - resolved "https://registry.yarnpkg.com/lefthook-linux-arm64/-/lefthook-linux-arm64-1.6.7.tgz#2c7663ed6363751fa264d1e54322b1dd05dc1970" - integrity sha512-3MAfA/cAgA7716C04XkSoyfMDXkOZDx9k2BkZdOwt35TBjxz6fkinYeeOvszGBSfeOFNQHIYYFgHazEaFVzrjQ== +lefthook-linux-arm64@1.6.8: + version "1.6.8" + resolved "https://registry.yarnpkg.com/lefthook-linux-arm64/-/lefthook-linux-arm64-1.6.8.tgz#91441885e12d8da096bffa14ef3eaccc5dde0c36" + integrity sha512-1VsEnfxWhs8YLMUnlYdbLBLldJrqJi/G2Isrvx0KBBu/nILxMmNa5GIQo8uqeeufmi/WVc8g3xgJtPxSp3NXnw== -lefthook-linux-x64@1.6.7: - version "1.6.7" - resolved "https://registry.yarnpkg.com/lefthook-linux-x64/-/lefthook-linux-x64-1.6.7.tgz#a3a24f465487f9cbf1df5ca2a2ce59e93f0e7329" - integrity sha512-VzgNM0bJyzakrhjFZbTYrwli0L6bY1bk6SKhyFAYToH8/rI6pjlinSgu1VTAamXhxmA7YaRB8/5OJEjhvb0aKg== +lefthook-linux-x64@1.6.8: + version "1.6.8" + resolved "https://registry.yarnpkg.com/lefthook-linux-x64/-/lefthook-linux-x64-1.6.8.tgz#aa3baa4581251dc508a109ebe470888f3a3e0b32" + integrity sha512-0e4GSPBhJkngO4qAX5bqJLYTftrBfulLiwbsWX6hx4SWFY3kFpCLtAYD8zfvfQaAfwb9Ieut2XnqcE9mNfI9+Q== -lefthook-windows-arm64@1.6.7: - version "1.6.7" - resolved "https://registry.yarnpkg.com/lefthook-windows-arm64/-/lefthook-windows-arm64-1.6.7.tgz#018479d901b00d2f5c4374bc2d137d972ab185de" - integrity sha512-naV4612JbrOCRZSWVS0Y1BzREHDLyCWC9eHqDG8XTGC1NJ/vM3ip2j9hHHF/GPSceazs82Tog2rSpJ9q8JZ0IQ== +lefthook-windows-arm64@1.6.8: + version "1.6.8" + resolved "https://registry.yarnpkg.com/lefthook-windows-arm64/-/lefthook-windows-arm64-1.6.8.tgz#6d3b98570bb93c3742d5fa42fc5ba04417eddb99" + integrity sha512-bVYRF4mBcT2T5/uN5pJpk9jqvik8JLtgRL+BxTKPshuVFO2nJczgdX1lWRnveGyz84DHwYgu+GwYl7PLjGU28A== -lefthook-windows-x64@1.6.7: - version "1.6.7" - resolved "https://registry.yarnpkg.com/lefthook-windows-x64/-/lefthook-windows-x64-1.6.7.tgz#240c55e3aac9425a55b1b9fd7f162bcc0a231e45" - integrity sha512-U0jwO5CTya9yo1G+946ULBhH3Nl6j+WOqYz7rWJQIIFNe0mvethmAv+aLKMNrAWgOZ+gX0A7++cqdUOl9LoVwQ== +lefthook-windows-x64@1.6.8: + version "1.6.8" + resolved "https://registry.yarnpkg.com/lefthook-windows-x64/-/lefthook-windows-x64-1.6.8.tgz#7f484559becb43237d8be8d83ea87f53cbaaebfa" + integrity sha512-cT3ZopXAFyEsfkRf+wRwINBPWUMYi2Wba59BqN8JU/Tfuuv7Of2e51u+VTsHMR+8+JdEt3A8Kl20xw24E8ccAg== -lefthook@^1.6.7: - version "1.6.7" - resolved "https://registry.yarnpkg.com/lefthook/-/lefthook-1.6.7.tgz#e6cbb0b2e7bc0110df64ea78eb354993c0990147" - integrity sha512-glQisTn0oMXfWv58MBE54wOPez8T06dqcEGrfz73RlvOi/kvbu59oockEvMYs4RfvowQirF0ncp+JHWJbDMRgQ== +lefthook@^1.6.8: + version "1.6.8" + resolved "https://registry.yarnpkg.com/lefthook/-/lefthook-1.6.8.tgz#d0f3a76c626d8945179dcb201c0756ec66be5e69" + integrity sha512-h+5S3FLhErIrVTz+uLaysS0kATlzCW8Wa1DUqpu0rYsimsEk/TrP9cMnTVd0UKq3Ks2ooq5pCUmnipJy5zl1VQ== optionalDependencies: - lefthook-darwin-arm64 "1.6.7" - lefthook-darwin-x64 "1.6.7" - lefthook-freebsd-arm64 "1.6.7" - lefthook-freebsd-x64 "1.6.7" - lefthook-linux-arm64 "1.6.7" - lefthook-linux-x64 "1.6.7" - lefthook-windows-arm64 "1.6.7" - lefthook-windows-x64 "1.6.7" + lefthook-darwin-arm64 "1.6.8" + lefthook-darwin-x64 "1.6.8" + lefthook-freebsd-arm64 "1.6.8" + lefthook-freebsd-x64 "1.6.8" + lefthook-linux-arm64 "1.6.8" + lefthook-linux-x64 "1.6.8" + lefthook-windows-arm64 "1.6.8" + lefthook-windows-x64 "1.6.8" levn@^0.4.1: version "0.4.1" @@ -5746,7 +5873,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== -lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21: +lodash@^4.17.11, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -6393,6 +6520,13 @@ parse-json@^5.0.0, parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +parse5@^7.0.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" + integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + dependencies: + entities "^4.4.0" + parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -6663,24 +6797,24 @@ postcss-minify-selectors@^6.0.2: dependencies: postcss-selector-parser "^6.0.15" -postcss-modules-extract-imports@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" - integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== +postcss-modules-extract-imports@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz#b4497cb85a9c0c4b5aabeb759bb25e8d89f15002" + integrity sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q== -postcss-modules-local-by-default@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.4.tgz#7cbed92abd312b94aaea85b68226d3dec39a14e6" - integrity sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q== +postcss-modules-local-by-default@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz#f1b9bd757a8edf4d8556e8d0f4f894260e3df78f" + integrity sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw== dependencies: icss-utils "^5.0.0" postcss-selector-parser "^6.0.2" postcss-value-parser "^4.1.0" -postcss-modules-scope@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.1.1.tgz#32cfab55e84887c079a19bbb215e721d683ef134" - integrity sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA== +postcss-modules-scope@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz#a43d28289a169ce2c15c00c4e64c0858e43457d5" + integrity sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ== dependencies: postcss-selector-parser "^6.0.4" @@ -6922,10 +7056,10 @@ pupa@^2.0.1: dependencies: escape-goat "^2.0.0" -qs@6.10.3: - version "6.10.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" - integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== dependencies: side-channel "^1.0.4" @@ -6956,10 +7090,10 @@ range-parser@^1.2.1, range-parser@~1.2.1: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -raw-body@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== dependencies: bytes "3.1.2" http-errors "2.0.0" @@ -7066,6 +7200,11 @@ regenerator-runtime@^0.13.4: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + regenerator-transform@^0.15.2: version "0.15.2" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" @@ -7368,10 +7507,10 @@ sass-loader@^14.1.1: dependencies: neo-async "^2.6.2" -sass@^1.72.0: - version "1.72.0" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.72.0.tgz#5b9978943fcfb32b25a6a5acb102fc9dabbbf41c" - integrity sha512-Gpczt3WA56Ly0Mn8Sl21Vj94s1axi9hDIzDFn9Ph9x3C3p4nNyvsqJoQyVXKou6cBlfFWEgRW4rT8Tb4i3XnVA== +sass@^1.74.1: + version "1.74.1" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.74.1.tgz#686fc227d3707dd25cb2925e1db8e4562be29319" + integrity sha512-w0Z9p/rWZWelb88ISOLyvqTWGmtmu2QJICqDBGyNnfG4OUnPX9BBjjYIXUpXCMOOg5MQWNpqzt876la1fsTvUA== dependencies: chokidar ">=3.0.0 <4.0.0" immutable "^4.0.0" @@ -7429,7 +7568,7 @@ semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.0.0, semver@^7.3.2, semver@^7.3.5, semver@^7.3.6, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0: +semver@^7.0.0, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.6, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0: version "7.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== @@ -7644,7 +7783,7 @@ sort-keys@^1.0.0: dependencies: is-plain-obj "^1.0.0" -"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.2.0: +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== @@ -7924,10 +8063,10 @@ stylelint-use-logical-spec@^5.0.1: resolved "https://registry.yarnpkg.com/stylelint-use-logical-spec/-/stylelint-use-logical-spec-5.0.1.tgz#d5aa254d615d373f18214297c0b49a03a6ca5980" integrity sha512-UfLB4LW6iG4r3cXxjxkiHQrFyhWFqt8FpNNngD+TyvgMWSokk5TYwTvBHS3atUvZhOogllTOe/PUrGE+4z84AA== -stylelint@^16.3.0: - version "16.3.0" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.3.0.tgz#4322a26c398e299aa1ee83db87282b16010a6122" - integrity sha512-hqC6xNTbQ5HRGQXfIW4HwXcx09raIFz4W4XFbraeqWqYRVVY/ibYvI0dsu0ORMQY8re2bpDdCAeIa2cm+QJ4Sw== +stylelint@^16.3.1: + version "16.3.1" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-16.3.1.tgz#006cc6cd4bd8e7b3acb1607bb8e8de85121b7847" + integrity sha512-/JOwQnBvxEKOT2RtNgGpBVXnCSMBgKOL2k7w0K52htwCyJls4+cHvc4YZgXlVoAZS9QJd2DgYAiRnja96pTgxw== dependencies: "@csstools/css-parser-algorithms" "^2.6.1" "@csstools/css-tokenizer" "^2.2.4" @@ -8028,10 +8167,10 @@ svgo@^3.2.0: csso "^5.0.5" picocolors "^1.0.0" -swiper@^11.0.7: - version "11.0.7" - resolved "https://registry.yarnpkg.com/swiper/-/swiper-11.0.7.tgz#fe51bb64546c2c21a1ec6914e7764af953443ded" - integrity sha512-cDfglW1B6uSmB6eB6pNmzDTNLmZtu5bWWa1vak0RU7fOI9qHjMzl7gVBvYSl34b0RU2N11HxxETJqQ5LeqI1cA== +swiper@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/swiper/-/swiper-11.1.0.tgz#3497b60d65d1320e427cdf11dfaad5c555283826" + integrity sha512-Pm78CgU7Wvg+w/MgIL/1NwMSLgx0XqFof25EnVyX8iZFCYJv5CppH7LHkBj43qW2k5Cp3Iz7FcdBxrox7XX2AQ== synckit@^0.6.0: version "0.6.2" @@ -8065,9 +8204,9 @@ tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1: integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== tar@^6.1.12: - version "6.1.15" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.15.tgz#c9738b0b98845a3b344d334b8fa3041aaba53a69" - integrity sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A== + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" @@ -8308,9 +8447,9 @@ undici-types@~5.26.4: integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== undici@^5.19.1: - version "5.28.3" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.3.tgz#a731e0eff2c3fcfd41c1169a869062be222d1e5b" - integrity sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA== + version "5.28.4" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" + integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== dependencies: "@fastify/busboy" "^2.0.0" @@ -8559,7 +8698,7 @@ vue-devtools@^5.1.4: resolved "https://registry.yarnpkg.com/vue-devtools/-/vue-devtools-5.1.4.tgz#265a7458ade2affb291739176964256b597fa302" integrity sha512-EBAEXvAHUinsPzoSiElps0JgtLXUnJXKIJbP6nfdz/R63VdKBMfJ34/rFip+4iT7iMbVS5lA4W6N1jq4Hj4LCg== -vue-eslint-parser@^9.0.1, vue-eslint-parser@^9.4.2: +vue-eslint-parser@^9.0.0, vue-eslint-parser@^9.0.1, vue-eslint-parser@^9.4.2: version "9.4.2" resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.4.2.tgz#02ffcce82042b082292f2d1672514615f0d95b6d" integrity sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ== @@ -8900,7 +9039,7 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml-eslint-parser@^1.2.1, yaml-eslint-parser@^1.2.2: +yaml-eslint-parser@^1.0.0, yaml-eslint-parser@^1.2.1, yaml-eslint-parser@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/yaml-eslint-parser/-/yaml-eslint-parser-1.2.2.tgz#1a9673ebe254328cfc2fa99f297f6d8c9364ccd8" integrity sha512-pEwzfsKbTrB8G3xc/sN7aw1v6A6c/pKxLAkjclnAyo5g5qOh6eL9WGu0o3cSDQZKrTNk4KL4lQSwZW+nBkANEg== @@ -8950,10 +9089,10 @@ yocto-queue@^1.0.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== -youtubei.js@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/youtubei.js/-/youtubei.js-9.1.0.tgz#bcf154c9fa21d3c8c1d00a5e10360d0a065c660e" - integrity sha512-C5GBJ4LgnS6vGAUkdIdQNOFFb5EZ1p3xBvUELNXmIG3Idr6vxWrKNBNy8ClZT3SuDVXaAJqDgF9b5jvY8lNKcg== +youtubei.js@^9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/youtubei.js/-/youtubei.js-9.2.0.tgz#26d521a0803ddd3ab5059a7b7eb5970514d883a4" + integrity sha512-Q157iNPlyB32477xU+1/+Pyz/Bxy9zLJ1sXLjn96qhBZ03wWHVwh2azeyz7jk13UvcrxZXtIYv9HHn2dFngGnQ== dependencies: jintr "^1.1.0" tslib "^2.5.0"