diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index cccd90a7479f9..5d34902f607ac 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -20,9 +20,7 @@ jobs:
- win-x64
- win-arm64
- osx-x64
- # `osx-arm64` disabled due to "macOS gatekeeper"
- # See details in https://github.com/FreeTubeApp/FreeTube/pull/2113
- # - osx-arm64
+ - osx-arm64
include:
- runtime: linux-x64
os: ubuntu-latest
@@ -36,8 +34,8 @@ jobs:
- runtime: osx-x64
os: macOS-latest
-# - runtime: osx-arm64
-# os: macOS-latest
+ - runtime: osx-arm64
+ os: macOS-latest
- runtime: win-x64
os: windows-latest
@@ -102,6 +100,19 @@ jobs:
if: contains(matrix.runtime, 'arm64')
run: yarn run build:arm64
+ - name: Convert X64 AppImage to static runtime
+ if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')
+ run: |
+ sudo apt install desktop-file-utils
+ cd build
+ appimage="FreeTube-${{ steps.versionNumber.outputs.result }}.AppImage"
+ wget "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage" -O ./appimagetool.AppImage
+ chmod +x ./"$appimage" ./appimagetool.AppImage
+ ./"$appimage" --appimage-extract && rm -f ./"$appimage"
+ ./appimagetool.AppImage --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 20 \
+ -n ./squashfs-root ./"$appimage"
+ rm -rf ./squashfs-root ./appimagetool.AppImage
+
- name: Upload Linux .zip x64 Artifact
uses: actions/upload-artifact@v4
if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')
@@ -300,12 +311,12 @@ jobs:
name: freetube-${{ steps.versionNumber.outputs.result }}-mac-x64.dmg
path: build/freetube-${{ steps.versionNumber.outputs.result }}.dmg
-# - name: Upload Mac arm64 .dmg Artifact
-# uses: actions/upload-artifact@v4
-# if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')
-# with:
-# name: freetube-${{ steps.versionNumber.outputs.result }}-mac-arm64.dmg
-# path: build/freetube-${{ steps.versionNumber.outputs.result }}-arm64.dmg
+ - name: Upload Mac arm64 .dmg Artifact
+ uses: actions/upload-artifact@v4
+ if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')
+ with:
+ name: freetube-${{ steps.versionNumber.outputs.result }}-mac-arm64.dmg
+ path: build/freetube-${{ steps.versionNumber.outputs.result }}-arm64.dmg
- name: Upload Mac x64 .zip Artifact
uses: actions/upload-artifact@v4
@@ -321,9 +332,16 @@ jobs:
name: freetube-${{ steps.versionNumber.outputs.result }}-mac-x64.7z
path: build/freetube-${{ steps.versionNumber.outputs.result }}-mac.7z
-# - name: Upload Mac arm64 .zip Artifact
-# uses: actions/upload-artifact@v4
-# if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')
-# with:
-# name: freetube-${{ steps.versionNumber.outputs.result }}-mac-arm64.zip
-# path: build/freetube-${{ steps.versionNumber.outputs.result }}-arm64-mac.zip
+ - name: Upload Mac arm64 .zip Artifact
+ uses: actions/upload-artifact@v4
+ if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')
+ with:
+ name: freetube-${{ steps.versionNumber.outputs.result }}-mac-arm64.zip
+ path: build/freetube-${{ steps.versionNumber.outputs.result }}-arm64-mac.zip
+
+ - name: Upload Mac arm64 .7z Artifact
+ uses: actions/upload-artifact@v4
+ if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')
+ with:
+ name: freetube-${{ steps.versionNumber.outputs.result }}-mac-arm64.7z
+ path: build/freetube-${{ steps.versionNumber.outputs.result }}-arm64-mac.7z
diff --git a/.github/workflows/flatpak.yml b/.github/workflows/flatpak.yml
index 94ece70dda5f5..217f4c926cc43 100644
--- a/.github/workflows/flatpak.yml
+++ b/.github/workflows/flatpak.yml
@@ -77,22 +77,22 @@ jobs:
date +"%Y-%m-%d" >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
- name: Update x64 File Location in yml File
- uses: mikefarah/yq@v4.44.5
+ uses: mikefarah/yq@v4.44.6
with:
# The Command which should be run
cmd: yq -i '.modules[0].sources[0].url = "https://github.com/FreeTubeApp/FreeTube/releases/download/v${{ steps.sub.outputs.result }}-beta/freetube-${{ steps.sub.outputs.result }}-linux-portable-x64.zip"' io.freetubeapp.FreeTube.yml
- name: Update x64 Hash in yml File
- uses: mikefarah/yq@v4.44.5
+ uses: mikefarah/yq@v4.44.6
with:
# The Command which should be run
cmd: yq -i '.modules[0].sources[0].sha256 = "${{ env.HASH_X64 }}"' io.freetubeapp.FreeTube.yml
- name: Update ARM File Location in yml File
- uses: mikefarah/yq@v4.44.5
+ uses: mikefarah/yq@v4.44.6
with:
# The Command which should be run
cmd: yq -i '.modules[0].sources[1].url = "https://github.com/FreeTubeApp/FreeTube/releases/download/v${{ steps.sub.outputs.result }}-beta/freetube-${{ steps.sub.outputs.result }}-linux-portable-arm64.zip"' io.freetubeapp.FreeTube.yml
- name: Update ARM Hash in yml File
- uses: mikefarah/yq@v4.44.5
+ uses: mikefarah/yq@v4.44.6
with:
# The Command which should be run
cmd: yq -i '.modules[0].sources[1].sha256 = "${{ env.HASH_ARM64 }}"' io.freetubeapp.FreeTube.yml
diff --git a/.github/workflows/no-response.yml b/.github/workflows/no-response.yml
index 1e1e82bb42689..b430c13ed588d 100644
--- a/.github/workflows/no-response.yml
+++ b/.github/workflows/no-response.yml
@@ -20,5 +20,5 @@ jobs:
This issue has been automatically closed because there has been no response to our request for more information from the original author.
With only the information that is currently in the issue, we don't have enough information to take action.
Please reach out if you have or find the answers we need so that we can investigate further.
- daysUntilClose: 14
+ daysUntilClose: 7
responseRequiredLabel: "U: Waiting for Response from Author"
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 572fcab1a55df..7438d0c110de5 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -20,9 +20,7 @@ jobs:
- win-x64
- win-arm64
- osx-x64
- # `osx-arm64` disabled due to "macOS gatekeeper"
- # See details in https://github.com/FreeTubeApp/FreeTube/pull/2113
- # - osx-arm64
+ - osx-arm64
include:
- runtime: linux-x64
os: ubuntu-latest
@@ -36,8 +34,8 @@ jobs:
- runtime: osx-x64
os: macOS-latest
-# - runtime: osx-arm64
-# os: macOS-latest
+ - runtime: osx-arm64
+ os: macOS-latest
- runtime: win-x64
os: windows-latest
@@ -73,6 +71,19 @@ jobs:
if: contains(matrix.runtime, 'arm64')
run: yarn run build:arm64
+ - name: Convert X64 AppImage to static runtime
+ if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')
+ run: |
+ sudo apt install desktop-file-utils
+ cd build
+ appimage="FreeTube-${{ steps.versionNumber.outputs.result }}.AppImage"
+ wget "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage" -O ./appimagetool.AppImage
+ chmod +x ./"$appimage" ./appimagetool.AppImage
+ ./"$appimage" --appimage-extract && rm -f ./"$appimage"
+ ./appimagetool.AppImage --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 20 \
+ -n ./squashfs-root ./"$appimage"
+ rm -rf ./squashfs-root ./appimagetool.AppImage
+
- name: Upload AppImage x64 Release
uses: actions/upload-release-asset@v1
if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64')
@@ -306,16 +317,16 @@ jobs:
asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}.dmg
asset_content_type: application/x-apple-diskimage
-# - name: Upload Mac arm64 .dmg Release
-# uses: actions/upload-release-asset@v1
-# if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')
-# env:
-# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-# with:
-# upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label}
-# asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-mac-arm64.dmg
-# asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-arm64.dmg
-# asset_content_type: application/x-apple-diskimage
+ - name: Upload Mac arm64 .dmg Release
+ uses: actions/upload-release-asset@v1
+ if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label}
+ asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-mac-arm64.dmg
+ asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-arm64.dmg
+ asset_content_type: application/x-apple-diskimage
- name: Upload Mac x64 .zip Release
uses: actions/upload-release-asset@v1
@@ -339,13 +350,24 @@ jobs:
asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-mac.7z
asset_content_type: application/x-7z-compressed
-# - name: Upload Mac arm64 .zip Release
-# uses: actions/upload-release-asset@v1
-# if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')
-# env:
-# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-# with:
-# upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label}
-# asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-mac-arm64.zip
-# asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-arm64-mac.zip
-# asset_content_type: application/x-apple-diskimage
+ - name: Upload Mac arm64 .zip Release
+ uses: actions/upload-release-asset@v1
+ if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label}
+ asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-mac-arm64.zip
+ asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-arm64-mac.zip
+ asset_content_type: application/x-apple-diskimage
+
+ - name: Upload Mac arm64 .7z Release
+ uses: actions/upload-release-asset@v1
+ if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64')
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label}
+ asset_name: freetube-${{ steps.getPackageInfo.outputs.version }}-mac-arm64.7z
+ asset_path: build/freetube-${{ steps.getPackageInfo.outputs.version }}-arm64-mac.7z
+ asset_content_type: application/x-7z-compressed
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index 6945419318d9a..354408edee5ef 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -14,14 +14,14 @@ jobs:
- uses: actions/stale@v9
with:
stale-issue-message: 'This issue is stale because it has been open 28 days with no activity. Remove stale label or comment or this will be closed in 7 days.'
- stale-pr-message: 'This PR is stale because it has been open 28 days with no activity. Remove stale label or comment or this will be closed in 14 days.'
+ stale-pr-message: 'This PR is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 14 days.'
close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.'
close-pr-message: 'This PR was closed because it has been stalled for 14 days with no activity.'
days-before-issue-stale: 28
- days-before-pr-stale: 28
+ days-before-pr-stale: 14
days-before-issue-close: 7
days-before-pr-close: 14
stale-issue-label: 'U: stale'
stale-pr-label: 'PR: stale'
exempt-pr-labels: 'PR: WIP'
- exempt-issue-labels: 'enhancement'
+ exempt-issue-labels: 'enhancement, U: reproduced'
diff --git a/_icons/iconGruvboxDarkSmall.svg b/_icons/iconGruvboxDarkSmall.svg
index e0223807047ce..e6dd6ad1595cf 100644
--- a/_icons/iconGruvboxDarkSmall.svg
+++ b/_icons/iconGruvboxDarkSmall.svg
@@ -1,4 +1 @@
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/_icons/iconGruvboxLightSmall.svg b/_icons/iconGruvboxLightSmall.svg
index 8750e7bb31c0e..a08e5c34f9830 100644
--- a/_icons/iconGruvboxLightSmall.svg
+++ b/_icons/iconGruvboxLightSmall.svg
@@ -1,4 +1 @@
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/_icons/textGruvboxDarkSmall.svg b/_icons/textGruvboxDarkSmall.svg
index 00ece3081910a..00e3080e7268f 100644
--- a/_icons/textGruvboxDarkSmall.svg
+++ b/_icons/textGruvboxDarkSmall.svg
@@ -1,4 +1 @@
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/_icons/textGruvboxLightSmall.svg b/_icons/textGruvboxLightSmall.svg
index 266390e3ad010..434c116ddd900 100644
--- a/_icons/textGruvboxLightSmall.svg
+++ b/_icons/textGruvboxLightSmall.svg
@@ -1,4 +1 @@
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/package.json b/package.json
index 0f56574e21736..647fdcf34f311 100644
--- a/package.json
+++ b/package.json
@@ -67,14 +67,14 @@
"path-browserify": "^1.0.1",
"portal-vue": "^2.1.7",
"process": "^0.11.10",
- "shaka-player": "^4.12.3",
+ "shaka-player": "^4.12.4",
"swiper": "^11.1.15",
"vue": "^2.7.16",
"vue-i18n": "^8.28.2",
"vue-observe-visibility": "^1.0.0",
"vue-router": "^3.6.5",
"vuex": "^3.6.2",
- "youtubei.js": "^11.0.1"
+ "youtubei.js": "^12.0.0"
},
"devDependencies": {
"@babel/core": "^7.26.0",
@@ -82,7 +82,7 @@
"@babel/preset-env": "^7.26.0",
"@double-great/stylelint-a11y": "^3.0.2",
"@eslint/js": "^9.16.0",
- "@intlify/eslint-plugin-vue-i18n": "^3.1.0",
+ "@intlify/eslint-plugin-vue-i18n": "^3.2.0",
"babel-loader": "^9.2.1",
"copy-webpack-plugin": "^12.0.2",
"css-loader": "^7.1.2",
@@ -100,15 +100,15 @@
"html-webpack-plugin": "^5.6.3",
"js-yaml": "^4.1.0",
"json-minimizer-webpack-plugin": "^5.0.0",
- "lefthook": "^1.8.5",
+ "lefthook": "^1.9.0",
"mini-css-extract-plugin": "^2.9.2",
"neostandard": "^0.11.9",
"npm-run-all2": "^7.0.1",
"postcss": "^8.4.49",
"postcss-scss": "^4.0.9",
"rimraf": "^6.0.1",
- "sass": "^1.81.0",
- "sass-loader": "^16.0.3",
+ "sass": "^1.82.0",
+ "sass-loader": "^16.0.4",
"stylelint": "^16.11.0",
"stylelint-config-sass-guidelines": "^12.1.0",
"stylelint-config-standard": "^36.0.1",
@@ -118,7 +118,7 @@
"vue-devtools": "^5.1.4",
"vue-eslint-parser": "^9.4.3",
"vue-loader": "^15.10.0",
- "webpack": "^5.96.1",
+ "webpack": "^5.97.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.1.0",
"yaml-eslint-parser": "^1.2.3"
diff --git a/src/main/index.js b/src/main/index.js
index eb3376c0776d2..4bd741a4accb9 100644
--- a/src/main/index.js
+++ b/src/main/index.js
@@ -254,13 +254,16 @@ function runApp() {
app.on('second-instance', (_, commandLine, __) => {
// Someone tried to run a second instance, we should focus our window
- if (mainWindow && typeof commandLine !== 'undefined') {
- if (mainWindow.isMinimized()) mainWindow.restore()
- mainWindow.focus()
-
+ if (typeof commandLine !== 'undefined') {
const url = getLinkUrl(commandLine)
- if (url) {
- mainWindow.webContents.send(IpcChannels.OPEN_URL, url)
+ if (mainWindow && mainWindow.webContents) {
+ if (mainWindow.isMinimized()) mainWindow.restore()
+ mainWindow.focus()
+
+ if (url) mainWindow.webContents.send(IpcChannels.OPEN_URL, url)
+ } else {
+ if (url) startupUrl = url
+ createWindow()
}
}
})
@@ -829,10 +832,11 @@ function runApp() {
})
}
- ipcMain.once(IpcChannels.APP_READY, () => {
+ ipcMain.on(IpcChannels.APP_READY, () => {
if (startupUrl) {
mainWindow.webContents.send(IpcChannels.OPEN_URL, startupUrl, { isLaunchLink: true })
}
+ startupUrl = null
})
function relaunch() {
@@ -1442,6 +1446,7 @@ function runApp() {
app.on('window-all-closed', () => {
// Clean up resources (datastores' compaction + Electron cache and storage data clearing)
cleanUpResources().finally(() => {
+ mainWindow = null
if (process.platform !== 'darwin') {
app.quit()
}
@@ -1511,6 +1516,7 @@ function runApp() {
mainWindow.webContents.send(IpcChannels.OPEN_URL, baseUrl(url))
} else {
startupUrl = baseUrl(url)
+ if (app.isReady()) createWindow()
}
})
diff --git a/src/renderer/App.js b/src/renderer/App.js
index 372be1665bbeb..5846ca3a2184d 100644
--- a/src/renderer/App.js
+++ b/src/renderer/App.js
@@ -2,7 +2,7 @@ import { defineComponent } from 'vue'
import { mapActions } from 'vuex'
import FtFlexBox from './components/ft-flex-box/ft-flex-box.vue'
import TopNav from './components/top-nav/top-nav.vue'
-import SideNav from './components/side-nav/side-nav.vue'
+import SideNav from './components/SideNav/SideNav.vue'
import FtNotificationBanner from './components/ft-notification-banner/ft-notification-banner.vue'
import FtPrompt from './components/ft-prompt/ft-prompt.vue'
import FtButton from './components/ft-button/ft-button.vue'
diff --git a/src/renderer/components/ChannelHome/ChannelHome.vue b/src/renderer/components/ChannelHome/ChannelHome.vue
index 31f0dec2f10b4..2e23da23cddc8 100644
--- a/src/renderer/components/ChannelHome/ChannelHome.vue
+++ b/src/renderer/components/ChannelHome/ChannelHome.vue
@@ -39,7 +39,7 @@
diff --git a/src/renderer/components/ExperimentalSettings/ExperimentalSettings.vue b/src/renderer/components/ExperimentalSettings/ExperimentalSettings.vue
index 792dd43532f3f..bec628ef17322 100644
--- a/src/renderer/components/ExperimentalSettings/ExperimentalSettings.vue
+++ b/src/renderer/components/ExperimentalSettings/ExperimentalSettings.vue
@@ -29,7 +29,7 @@
+
+
diff --git a/src/renderer/components/ft-settings-section/ft-settings-section.scss b/src/renderer/components/FtSettingsSection/FtSettingsSection.scss
similarity index 100%
rename from src/renderer/components/ft-settings-section/ft-settings-section.scss
rename to src/renderer/components/FtSettingsSection/FtSettingsSection.scss
diff --git a/src/renderer/components/ft-settings-section/ft-settings-section.vue b/src/renderer/components/FtSettingsSection/FtSettingsSection.vue
similarity index 55%
rename from src/renderer/components/ft-settings-section/ft-settings-section.vue
rename to src/renderer/components/FtSettingsSection/FtSettingsSection.vue
index c748d931a32fe..28120f65cd5c3 100644
--- a/src/renderer/components/ft-settings-section/ft-settings-section.vue
+++ b/src/renderer/components/FtSettingsSection/FtSettingsSection.vue
@@ -11,5 +11,13 @@
-
-
+
+
+
diff --git a/src/renderer/components/ParentalControlSettings.vue b/src/renderer/components/ParentalControlSettings.vue
index 5f8541ed03e38..433b3e4927d08 100644
--- a/src/renderer/components/ParentalControlSettings.vue
+++ b/src/renderer/components/ParentalControlSettings.vue
@@ -32,7 +32,7 @@
+
+
diff --git a/src/renderer/components/side-nav-more-options/side-nav-more-options.css b/src/renderer/components/SideNavMoreOptions/SideNavMoreOptions.css
similarity index 100%
rename from src/renderer/components/side-nav-more-options/side-nav-more-options.css
rename to src/renderer/components/SideNavMoreOptions/SideNavMoreOptions.css
diff --git a/src/renderer/components/side-nav-more-options/side-nav-more-options.vue b/src/renderer/components/SideNavMoreOptions/SideNavMoreOptions.vue
similarity index 79%
rename from src/renderer/components/side-nav-more-options/side-nav-more-options.vue
rename to src/renderer/components/SideNavMoreOptions/SideNavMoreOptions.vue
index 127082d686fe4..6fd3b27f043b5 100644
--- a/src/renderer/components/side-nav-more-options/side-nav-more-options.vue
+++ b/src/renderer/components/SideNavMoreOptions/SideNavMoreOptions.vue
@@ -10,7 +10,7 @@
@keydown.space.prevent="openMoreOptions = !openMoreOptions"
@keydown.enter.prevent="openMoreOptions = !openMoreOptions"
>
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/src/renderer/components/ThemeSettings.vue b/src/renderer/components/ThemeSettings.vue
index 4062a97c27f25..9815a2b0a4f23 100644
--- a/src/renderer/components/ThemeSettings.vue
+++ b/src/renderer/components/ThemeSettings.vue
@@ -95,7 +95,7 @@
import { computed, ref } from 'vue'
import { useI18n } from '../composables/use-i18n-polyfill'
-import FtSettingsSection from './ft-settings-section/ft-settings-section.vue'
+import FtSettingsSection from './FtSettingsSection/FtSettingsSection.vue'
import FtSelect from './ft-select/ft-select.vue'
import FtToggleSwitch from './ft-toggle-switch/ft-toggle-switch.vue'
import FtSlider from './ft-slider/ft-slider.vue'
diff --git a/src/renderer/components/WatchVideoDescription/WatchVideoDescription.css b/src/renderer/components/WatchVideoDescription/WatchVideoDescription.css
index c7b2a437e55d8..ae0da75e3b2db 100644
--- a/src/renderer/components/WatchVideoDescription/WatchVideoDescription.css
+++ b/src/renderer/components/WatchVideoDescription/WatchVideoDescription.css
@@ -1,6 +1,9 @@
.videoDescription {
+ position: relative;
+ display: flex;
+ flex-direction: column-reverse;
overflow-y: auto;
- max-block-size: 300px;
+ max-block-size: 20lh;
}
.description {
@@ -9,3 +12,46 @@
white-space: pre-wrap;
overflow-wrap: anywhere;
}
+
+.descriptionStatus {
+ margin: 0;
+ text-decoration: underline;
+ cursor: pointer;
+ color: var(--title-color);
+}
+
+.videoDescription.short .descriptionStatus {
+ position: absolute;
+ inset-block-end: calc(1lh + 12px);
+ padding-block: 2px;
+ inset-inline-end: 16px;
+ padding-inline-start: 40px;
+ background: linear-gradient(270deg, var(--card-bg-color) 75%, transparent 100%);
+ text-decoration: none;
+}
+
+.videoDescription:not(.short) .descriptionStatus {
+ position: relative;
+ order: 0;
+ margin-block-start: 1em;
+}
+
+.videoDescription.short .description {
+ max-block-size: 4lh;
+ overflow: hidden;
+}
+
+.videoDescription:not(.short) .description {
+ order: 1;
+}
+
+.videoDescription .overlay {
+ position: absolute;
+ cursor: pointer;
+ inset: 0;
+ transition: background-color 200ms ease;
+}
+
+.videoDescription .overlay:hover {
+ background-color: var(--accent-color-opacity1);
+}
diff --git a/src/renderer/components/WatchVideoDescription/WatchVideoDescription.vue b/src/renderer/components/WatchVideoDescription/WatchVideoDescription.vue
index 9e3ecc12038e1..a2534db231c5e 100644
--- a/src/renderer/components/WatchVideoDescription/WatchVideoDescription.vue
+++ b/src/renderer/components/WatchVideoDescription/WatchVideoDescription.vue
@@ -1,9 +1,40 @@
+
+
+ {{ $t("Description.Collapse Description") }}
+
+
+ {{ $t("Description.Expand Description") }}
+
+
+
import autolinker from 'autolinker'
+import { onMounted, ref } from 'vue'
import FtCard from '../ft-card/ft-card.vue'
import FtTimestampCatcher from '../FtTimestampCatcher.vue'
@@ -31,6 +63,9 @@ const props = defineProps({
const emit = defineEmits(['timestamp-event'])
let shownDescription = ''
+const descriptionContainer = ref()
+const showFullDescription = ref(false)
+const showControls = ref(false)
if (props.descriptionHtml !== '') {
const parsed = parseDescriptionHtml(props.descriptionHtml)
@@ -58,6 +93,37 @@ function onTimestamp(timestamp) {
emit('timestamp-event', timestamp)
}
+/**
+ * Enables user to view entire contents of description
+ */
+function expandDescription() {
+ showFullDescription.value = true
+}
+
+/**
+ * Enables user to collapse contents of description
+ */
+function collapseDescription() {
+ showFullDescription.value = false
+}
+
+/**
+ * Returns true when description content does not overflow description container
+ * Useful for hiding description expansion/contraction controls
+ */
+function isShortDescription() {
+ const descriptionElem = descriptionContainer.value?.$el
+ return descriptionElem?.clientHeight >= descriptionElem?.scrollHeight
+}
+
+onMounted(() => {
+ // To verify whether or not the description is too short for displaying
+ // description controls, we need to check the description's dimensions.
+ // The only way to make this work is to check on mount.
+ showFullDescription.value = isShortDescription()
+ showControls.value = !showFullDescription.value
+})
+
/**
* @param {string} descriptionText
* @returns {string}
diff --git a/src/renderer/components/data-settings/data-settings.js b/src/renderer/components/data-settings/data-settings.js
index c13adaf4b7927..e479793ca255a 100644
--- a/src/renderer/components/data-settings/data-settings.js
+++ b/src/renderer/components/data-settings/data-settings.js
@@ -1,5 +1,5 @@
import { defineComponent } from 'vue'
-import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue'
+import FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'
import { mapActions, mapMutations } from 'vuex'
import FtButton from '../ft-button/ft-button.vue'
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
@@ -13,13 +13,12 @@ import {
escapeHTML,
getTodayDateStrLocalTimezone,
readFileWithPicker,
- showSaveDialog,
showToast,
- writeFileFromDialog,
+ writeFileWithPicker,
} from '../../helpers/utils'
const IMPORT_DIRECTORY_ID = 'data-settings-import'
-const IMPORT_START_IN_DIRECTORY = 'downloads'
+const START_IN_DIRECTORY = 'downloads'
export default defineComponent({
name: 'DataSettings',
@@ -94,7 +93,7 @@ export default defineComponent({
'application/xml': ['.xml', '.opml']
},
IMPORT_DIRECTORY_ID,
- IMPORT_START_IN_DIRECTORY
+ START_IN_DIRECTORY
)
} catch (err) {
const message = this.$t('Settings.Data Settings.Unable to read file')
@@ -435,33 +434,20 @@ export default defineComponent({
const dateStr = getTodayDateStrLocalTimezone()
const exportFileName = 'freetube-subscriptions-' + dateStr + '.db'
- const options = {
- defaultPath: exportFileName,
- filters: [
- {
- name: this.$t('Settings.Data Settings.Subscription File'),
- extensions: ['db']
- }
- ]
- }
-
- await this.promptAndWriteToFile(options, subscriptionsDb, this.$t('Settings.Data Settings.Subscriptions have been successfully exported'))
+ await this.promptAndWriteToFile(
+ exportFileName,
+ subscriptionsDb,
+ this.$t('Settings.Data Settings.Subscription File'),
+ 'application/x-freetube-db',
+ '.db',
+ this.$t('Settings.Data Settings.Subscriptions have been successfully exported')
+ )
},
exportYouTubeSubscriptions: async function () {
const dateStr = getTodayDateStrLocalTimezone()
const exportFileName = 'youtube-subscriptions-' + dateStr + '.json'
- const options = {
- defaultPath: exportFileName,
- filters: [
- {
- name: this.$t('Settings.Data Settings.Subscription File'),
- extensions: ['json']
- }
- ]
- }
-
const subscriptionsObject = this.profileList[0].subscriptions.map((channel) => {
const object = {
contentDetails: {
@@ -498,23 +484,20 @@ export default defineComponent({
return object
})
- await this.promptAndWriteToFile(options, JSON.stringify(subscriptionsObject), this.$t('Settings.Data Settings.Subscriptions have been successfully exported'))
+ await this.promptAndWriteToFile(
+ exportFileName,
+ JSON.stringify(subscriptionsObject),
+ this.$t('Settings.Data Settings.Subscription File'),
+ 'application/json',
+ '.json',
+ this.$t('Settings.Data Settings.Subscriptions have been successfully exported')
+ )
},
exportOpmlYouTubeSubscriptions: async function () {
const dateStr = getTodayDateStrLocalTimezone()
const exportFileName = 'youtube-subscriptions-' + dateStr + '.opml'
- const options = {
- defaultPath: exportFileName,
- filters: [
- {
- name: this.$t('Settings.Data Settings.Subscription File'),
- extensions: ['opml']
- }
- ]
- }
-
let opmlData = ''
this.profileList[0].subscriptions.forEach((channel) => {
@@ -526,22 +509,20 @@ export default defineComponent({
opmlData += ''
- await this.promptAndWriteToFile(options, opmlData, this.$t('Settings.Data Settings.Subscriptions have been successfully exported'))
+ await this.promptAndWriteToFile(
+ exportFileName,
+ opmlData,
+ this.$t('Settings.Data Settings.Subscription File'),
+ 'application/xml',
+ '.opml',
+ this.$t('Settings.Data Settings.Subscriptions have been successfully exported')
+ )
},
exportCsvYouTubeSubscriptions: async function () {
const dateStr = getTodayDateStrLocalTimezone()
const exportFileName = 'youtube-subscriptions-' + dateStr + '.csv'
- const options = {
- defaultPath: exportFileName,
- filters: [
- {
- name: this.$t('Settings.Data Settings.Subscription File'),
- extensions: ['csv']
- }
- ]
- }
let exportText = 'Channel ID,Channel URL,Channel title\n'
this.profileList[0].subscriptions.forEach((channel) => {
const channelUrl = `https://www.youtube.com/channel/${channel.id}`
@@ -552,23 +533,20 @@ export default defineComponent({
})
exportText += '\n'
- await this.promptAndWriteToFile(options, exportText, this.$t('Settings.Data Settings.Subscriptions have been successfully exported'))
+ await this.promptAndWriteToFile(
+ exportFileName,
+ exportText,
+ this.$t('Settings.Data Settings.Subscription File'),
+ 'text/csv',
+ '.csv',
+ this.$t('Settings.Data Settings.Subscriptions have been successfully exported')
+ )
},
exportNewPipeSubscriptions: async function () {
const dateStr = getTodayDateStrLocalTimezone()
const exportFileName = 'newpipe-subscriptions-' + dateStr + '.json'
- const options = {
- defaultPath: exportFileName,
- filters: [
- {
- name: this.$t('Settings.Data Settings.Subscription File'),
- extensions: ['json']
- }
- ]
- }
-
const newPipeObject = {
app_version: '0.19.8',
app_version_int: 953,
@@ -586,7 +564,14 @@ export default defineComponent({
newPipeObject.subscriptions.push(subscription)
})
- await this.promptAndWriteToFile(options, JSON.stringify(newPipeObject), this.$t('Settings.Data Settings.Subscriptions have been successfully exported'))
+ await this.promptAndWriteToFile(
+ exportFileName,
+ JSON.stringify(newPipeObject),
+ this.$t('Settings.Data Settings.Subscription File'),
+ 'application/json',
+ '.json',
+ this.$t('Settings.Data Settings.Subscriptions have been successfully exported')
+ )
},
importHistory: async function () {
@@ -599,7 +584,7 @@ export default defineComponent({
'application/json': '.json'
},
IMPORT_DIRECTORY_ID,
- IMPORT_START_IN_DIRECTORY
+ START_IN_DIRECTORY
)
} catch (err) {
const message = this.$t('Settings.Data Settings.Unable to read file')
@@ -778,17 +763,14 @@ export default defineComponent({
const dateStr = getTodayDateStrLocalTimezone()
const exportFileName = 'freetube-history-' + dateStr + '.db'
- const options = {
- defaultPath: exportFileName,
- filters: [
- {
- name: this.$t('Settings.Data Settings.Playlist File'),
- extensions: ['db']
- }
- ]
- }
-
- await this.promptAndWriteToFile(options, historyDb, this.$t('Settings.Data Settings.All watched history has been successfully exported'))
+ await this.promptAndWriteToFile(
+ exportFileName,
+ historyDb,
+ this.$t('Settings.Data Settings.History File'),
+ 'application/x-freetube-db',
+ '.db',
+ this.$t('Settings.Data Settings.All watched history has been successfully exported')
+ )
},
importPlaylists: async function () {
@@ -800,7 +782,7 @@ export default defineComponent({
'application/x-freetube-db': '.db'
},
IMPORT_DIRECTORY_ID,
- IMPORT_START_IN_DIRECTORY
+ START_IN_DIRECTORY
)
} catch (err) {
const message = this.$t('Settings.Data Settings.Unable to read file')
@@ -978,21 +960,18 @@ export default defineComponent({
const dateStr = getTodayDateStrLocalTimezone()
const exportFileName = 'freetube-playlists-' + dateStr + '.db'
- const options = {
- defaultPath: exportFileName,
- filters: [
- {
- name: 'Database File',
- extensions: ['db']
- }
- ]
- }
-
const playlistsDb = this.allPlaylists.map(playlist => {
return JSON.stringify(playlist)
}).join('\n') + '\n'// a trailing line is expected
- await this.promptAndWriteToFile(options, playlistsDb, this.$t('Settings.Data Settings.All playlists has been successfully exported'))
+ await this.promptAndWriteToFile(
+ exportFileName,
+ playlistsDb,
+ this.$t('Settings.Data Settings.Playlist File'),
+ 'application/x-freetube-db',
+ '.db',
+ this.$t('Settings.Data Settings.All playlists has been successfully exported')
+ )
},
exportPlaylistsForOlderVersionsSometimes: function () {
@@ -1007,16 +986,6 @@ export default defineComponent({
const dateStr = getTodayDateStrLocalTimezone()
const exportFileName = 'freetube-playlists-as-single-favorites-playlist-' + dateStr + '.db'
- const options = {
- defaultPath: exportFileName,
- filters: [
- {
- name: 'Database File',
- extensions: ['db']
- }
- ]
- }
-
const favoritesPlaylistData = {
playlistName: 'Favorites',
protected: true,
@@ -1041,7 +1010,14 @@ export default defineComponent({
})
})
- await this.promptAndWriteToFile(options, JSON.stringify([favoritesPlaylistData]), this.$t('Settings.Data Settings.All playlists has been successfully exported'))
+ await this.promptAndWriteToFile(
+ exportFileName,
+ JSON.stringify([favoritesPlaylistData]),
+ this.$t('Settings.Data Settings.Playlist File'),
+ 'application/x-freetube-db',
+ '.db',
+ this.$t('Settings.Data Settings.All playlists has been successfully exported')
+ )
},
convertOldFreeTubeFormatToNew(oldData) {
@@ -1075,22 +1051,32 @@ export default defineComponent({
return convertedData
},
- promptAndWriteToFile: async function (saveOptions, content, successMessage) {
- const response = await showSaveDialog(saveOptions)
- if (response.canceled || response.filePath === '') {
- // User canceled the save dialog
- return
- }
-
+ promptAndWriteToFile: async function (
+ fileName,
+ content,
+ fileTypeDescription,
+ mimeType,
+ fileExtension,
+ successMessage
+ ) {
try {
- await writeFileFromDialog(response, content)
- } catch (writeErr) {
+ const response = await writeFileWithPicker(
+ fileName,
+ content,
+ fileTypeDescription,
+ mimeType,
+ fileExtension,
+ 'data-settings-export',
+ START_IN_DIRECTORY
+ )
+
+ if (response) {
+ showToast(successMessage)
+ }
+ } catch (error) {
const message = this.$t('Settings.Data Settings.Unable to write file')
- showToast(`${message}: ${writeErr}`)
- return
+ showToast(`${message}: ${error}`)
}
-
- showToast(successMessage)
},
isChannelSubscribed(channelId, subscriptions) {
diff --git a/src/renderer/components/distraction-settings/distraction-settings.js b/src/renderer/components/distraction-settings/distraction-settings.js
index 9f7933e462fc6..37fa451bc2325 100644
--- a/src/renderer/components/distraction-settings/distraction-settings.js
+++ b/src/renderer/components/distraction-settings/distraction-settings.js
@@ -1,6 +1,6 @@
import { defineComponent } from 'vue'
import { mapActions } from 'vuex'
-import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue'
+import FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
import FtInputTags from '../../components/ft-input-tags/ft-input-tags.vue'
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
diff --git a/src/renderer/components/download-settings/download-settings.js b/src/renderer/components/download-settings/download-settings.js
index a0ad9efa067da..9755d672e3450 100644
--- a/src/renderer/components/download-settings/download-settings.js
+++ b/src/renderer/components/download-settings/download-settings.js
@@ -1,5 +1,5 @@
import { defineComponent } from 'vue'
-import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue'
+import FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
import FtSelect from '../ft-select/ft-select.vue'
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 b54766cee5b65..4722596b4003e 100644
--- a/src/renderer/components/external-player-settings/external-player-settings.js
+++ b/src/renderer/components/external-player-settings/external-player-settings.js
@@ -1,6 +1,6 @@
import { defineComponent } from 'vue'
import { mapActions } from 'vuex'
-import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue'
+import FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'
import FtSelect from '../ft-select/ft-select.vue'
import FtInput from '../ft-input/ft-input.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
diff --git a/src/renderer/components/ft-settings-menu/ft-settings-menu.js b/src/renderer/components/ft-settings-menu/ft-settings-menu.js
deleted file mode 100644
index 5378063a98031..0000000000000
--- a/src/renderer/components/ft-settings-menu/ft-settings-menu.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import { defineComponent } from 'vue'
-
-export default defineComponent({
- name: 'FtSettingsMenu',
- props: {
- settingsSections: {
- type: Array,
- required: true
- },
- },
- emits: ['navigate-to-section'],
- methods: {
- goToSettingsSection: function (sectionType) {
- this.$emit('navigate-to-section', sectionType)
- }
- }
-})
diff --git a/src/renderer/components/ft-settings-section/ft-settings-section.js b/src/renderer/components/ft-settings-section/ft-settings-section.js
deleted file mode 100644
index 42715cbd13032..0000000000000
--- a/src/renderer/components/ft-settings-section/ft-settings-section.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { defineComponent } from 'vue'
-
-export default defineComponent({
- name: 'FtSettingsSection',
- props: {
- title: {
- type: String,
- required: true
- },
- }
-})
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.css b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.css
index 343fe610211e9..7a70c5910aa2c 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.css
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.css
@@ -243,6 +243,32 @@
}
}
+@media only screen and (width >= 1000px) {
+ :deep(.shaka-bottom-controls) {
+ /* remove some bottom padding since the seek bar is above */
+ padding-bottom: 0;
+
+ /* make seekbar take full width on non-mobile devices */
+ width: 100%;
+ }
+
+ /* increase height of captions area since we remove the padding-bottom below the seekbar */
+ :deep(.shaka-controls-container[shown='true']~.shaka-text-container) {
+ bottom: 12.5%;
+ }
+
+ :deep(.shaka-controls-button-panel>button) {
+ height: 40px;
+ line-height: 0.5;
+ }
+
+ :deep(.shaka-tooltips-on button:active::after),
+ :deep(.shaka-tooltips-on button:focus-visible::after),
+ :deep(.shaka-tooltips-on button:hover::after) {
+ margin-bottom: 8px;
+ }
+}
+
@media only screen and (width <=1350px) {
:deep(.theatre-button) {
display: none;
diff --git a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
index 473f1005d9146..bf53f9182a2a9 100644
--- a/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
+++ b/src/renderer/components/ft-shaka-video-player/ft-shaka-video-player.js
@@ -122,7 +122,7 @@ export default defineComponent({
vrProjection: {
type: String,
default: null
- }
+ },
},
emits: [
'error',
@@ -245,6 +245,12 @@ export default defineComponent({
return store.getters.getDefaultSkipInterval
})
+ watch(defaultSkipInterval, (newValue) => {
+ ui.configure({
+ tapSeekDistance: newValue
+ })
+ })
+
/** @type {import('vue').ComputedRef} */
const defaultQuality = computed(() => {
const value = store.getters.getDefaultQuality
@@ -839,6 +845,7 @@ export default defineComponent({
addBigPlayButton: displayVideoPlayButton.value,
enableFullscreenOnRotation: enterFullscreenOnDisplayRotate.value,
playbackRates: playbackRates.value,
+ tapSeekDistance: defaultSkipInterval.value,
// we have our own ones (shaka-player's ones are quite limited)
enableKeyboardPlaybackControls: false,
@@ -1179,7 +1186,8 @@ export default defineComponent({
if (url.hostname.endsWith('.youtube.com') && url.pathname === '/api/timedtext' &&
url.searchParams.get('caps') === 'asr' && url.searchParams.get('kind') === 'asr' && url.searchParams.get('fmt') === 'vtt') {
const stringBody = new TextDecoder().decode(response.data)
- const cleaned = stringBody.replaceAll(/ align:start position:0%$/gm, '')
+ // position:0% for LTR text and position:100% for RTL text
+ const cleaned = stringBody.replaceAll(/ align:start position:(?:10)?0%$/gm, '')
response.data = new TextEncoder().encode(cleaned).buffer
}
@@ -1527,7 +1535,8 @@ export default defineComponent({
const format = screenshotFormat.value
const mimeType = `image/${format === 'jpg' ? 'jpeg' : format}`
- const imageQuality = format === 'jpg' ? screenshotQuality.value / 100 : 1
+ // imageQuality is ignored for pngs, so it is still okay to pass the quality value
+ const imageQuality = screenshotQuality.value / 100
let filename
try {
@@ -2476,7 +2485,8 @@ export default defineComponent({
const response = await fetch(caption.url)
let text = await response.text()
- text = text.replaceAll(/ align:start position:0%$/gm, '')
+ // position:0% for LTR text and position:100% for RTL text
+ text = text.replaceAll(/ align:start position:(?:10)?0%$/gm, '')
const url = `data:${caption.mimeType};charset=utf-8,${encodeURIComponent(text)}`
diff --git a/src/renderer/components/general-settings/general-settings.js b/src/renderer/components/general-settings/general-settings.js
index ac9c2f68c0ae5..c8e089f3967ac 100644
--- a/src/renderer/components/general-settings/general-settings.js
+++ b/src/renderer/components/general-settings/general-settings.js
@@ -1,6 +1,6 @@
import { defineComponent } from 'vue'
import { mapActions, mapMutations } from 'vuex'
-import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue'
+import FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'
import FtSelect from '../ft-select/ft-select.vue'
import FtInput from '../ft-input/ft-input.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
diff --git a/src/renderer/components/player-settings/player-settings.js b/src/renderer/components/player-settings/player-settings.js
index 4705f5ec3a612..a2afa7e5dbad9 100644
--- a/src/renderer/components/player-settings/player-settings.js
+++ b/src/renderer/components/player-settings/player-settings.js
@@ -1,6 +1,6 @@
import { defineComponent } from 'vue'
import { mapActions } from 'vuex'
-import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue'
+import FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'
import FtSelect from '../ft-select/ft-select.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
import FtSlider from '../ft-slider/ft-slider.vue'
@@ -51,11 +51,13 @@ export default defineComponent({
],
screenshotFormatNames: [
'PNG',
- 'JPEG'
+ 'JPEG',
+ 'WebP'
],
screenshotFormatValues: [
'png',
- 'jpg'
+ 'jpg',
+ 'webp'
],
screenshotFolderPlaceholder: '',
screenshotFilenameExample: '',
@@ -95,6 +97,10 @@ export default defineComponent({
return this.backendPreference !== 'invidious' && !this.backendFallback
},
+ defaultAutoplayInterruptionIntervalHours: function () {
+ return parseInt(this.$store.getters.getDefaultAutoplayInterruptionIntervalHours)
+ },
+
defaultSkipInterval: function () {
return parseInt(this.$store.getters.getDefaultSkipInterval)
},
@@ -286,6 +292,7 @@ export default defineComponent({
...mapActions([
'updateAutoplayVideos',
'updateAutoplayPlaylists',
+ 'updateDefaultAutoplayInterruptionIntervalHours',
'updatePlayNextVideo',
'updateEnableSubtitlesByDefault',
'updateProxyVideos',
diff --git a/src/renderer/components/player-settings/player-settings.vue b/src/renderer/components/player-settings/player-settings.vue
index 0c736a398c539..77677a0591ab3 100644
--- a/src/renderer/components/player-settings/player-settings.vue
+++ b/src/renderer/components/player-settings/player-settings.vue
@@ -82,15 +82,6 @@
-
+
+
diff --git a/src/renderer/components/playlist-info/playlist-info.js b/src/renderer/components/playlist-info/playlist-info.js
index 23854abf54513..51348d3e9256e 100644
--- a/src/renderer/components/playlist-info/playlist-info.js
+++ b/src/renderer/components/playlist-info/playlist-info.js
@@ -11,8 +11,7 @@ import {
formatNumber,
showToast,
getTodayDateStrLocalTimezone,
- writeFileFromDialog,
- showSaveDialog,
+ writeFileWithPicker,
} from '../../helpers/utils'
import debounce from 'lodash.debounce'
import thumbnailPlaceholder from '../../assets/img/thumbnail_placeholder.svg'
@@ -429,34 +428,28 @@ export default defineComponent({
const title = this.selectedUserPlaylist.playlistName.replaceAll(' ', '_').replaceAll(/["%*/:<>?\\|]/g, '_')
const exportFileName = 'freetube-playlist-' + title + '-' + dateStr + '.db'
- const options = {
- defaultPath: exportFileName,
- filters: [
- {
- name: 'Database File',
- extensions: ['db']
- }
- ]
- }
-
const data = JSON.stringify(this.selectedUserPlaylist) + '\n'
// See data-settings.js `promptAndWriteToFile`
- const response = await showSaveDialog(options)
- if (response.canceled || response.filePath === '') {
- // User canceled the save dialog
- return
- }
try {
- await writeFileFromDialog(response, data)
- } catch (writeErr) {
+ const response = await writeFileWithPicker(
+ exportFileName,
+ data,
+ this.$t('Settings.Data Settings.Playlist File'),
+ 'application/x-freetube-db',
+ '.db',
+ 'single-playlist-export',
+ 'downloads'
+ )
+
+ if (response) {
+ showToast(this.$t('User Playlists.The playlist has been successfully exported'))
+ }
+ } catch (error) {
const message = this.$t('Settings.Data Settings.Unable to write file')
- showToast(`${message}: ${writeErr}`)
- return
+ showToast(`${message}: ${error}`)
}
-
- showToast(this.$t('User Playlists.The playlist has been successfully exported'))
},
exitEditMode: function () {
diff --git a/src/renderer/components/privacy-settings/privacy-settings.js b/src/renderer/components/privacy-settings/privacy-settings.js
index 98b9a266ced9d..f9855341ef80d 100644
--- a/src/renderer/components/privacy-settings/privacy-settings.js
+++ b/src/renderer/components/privacy-settings/privacy-settings.js
@@ -1,6 +1,6 @@
import { defineComponent } from 'vue'
import { mapActions } from 'vuex'
-import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue'
+import FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'
import FtButton from '../ft-button/ft-button.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
diff --git a/src/renderer/components/proxy-settings/proxy-settings.js b/src/renderer/components/proxy-settings/proxy-settings.js
index 901ca21d88bf0..dcd560f92a454 100644
--- a/src/renderer/components/proxy-settings/proxy-settings.js
+++ b/src/renderer/components/proxy-settings/proxy-settings.js
@@ -1,6 +1,6 @@
import { defineComponent } from 'vue'
import { mapActions } from 'vuex'
-import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue'
+import FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
import FtButton from '../ft-button/ft-button.vue'
import FtSelect from '../ft-select/ft-select.vue'
diff --git a/src/renderer/components/side-nav-more-options/side-nav-more-options.js b/src/renderer/components/side-nav-more-options/side-nav-more-options.js
deleted file mode 100644
index 83bae2a4de7ff..0000000000000
--- a/src/renderer/components/side-nav-more-options/side-nav-more-options.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import { defineComponent } from 'vue'
-
-export default defineComponent({
- name: 'SideNav',
- data: function () {
- return {
- openMoreOptions: false
- }
- },
- computed: {
- backendFallback: function () {
- return this.$store.getters.getBackendFallback
- },
- backendPreference: function () {
- return this.$store.getters.getBackendPreference
- },
- hidePopularVideos: function () {
- return this.$store.getters.getHidePopularVideos
- },
- hideTrendingVideos: function () {
- return this.$store.getters.getHideTrendingVideos
- },
- hideLabelsSideBar: function () {
- return this.$store.getters.getHideLabelsSideBar
- },
- applyNavIconExpand: function() {
- return {
- navIconExpand: this.hideLabelsSideBar
- }
- }
- }
-})
diff --git a/src/renderer/components/side-nav/side-nav.js b/src/renderer/components/side-nav/side-nav.js
deleted file mode 100644
index 72aad5874e09b..0000000000000
--- a/src/renderer/components/side-nav/side-nav.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import { defineComponent } from 'vue'
-import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
-import SideNavMoreOptions from '../side-nav-more-options/side-nav-more-options.vue'
-import { youtubeImageUrlToInvidious } from '../../helpers/api/invidious'
-import { deepCopy, localizeAndAddKeyboardShortcutToActionTitle } from '../../helpers/utils'
-import { KeyboardShortcuts } from '../../../constants'
-
-export default defineComponent({
- name: 'SideNav',
- components: {
- 'ft-flex-box': FtFlexBox,
- 'side-nav-more-options': SideNavMoreOptions
- },
- computed: {
- isOpen: function () {
- return this.$store.getters.getIsSideNavOpen
- },
- backendFallback: function () {
- return this.$store.getters.getBackendFallback
- },
- backendPreference: function () {
- return this.$store.getters.getBackendPreference
- },
- currentInvidiousInstanceUrl: function () {
- return this.$store.getters.getCurrentInvidiousInstanceUrl
- },
- profileList: function () {
- return this.$store.getters.getProfileList
- },
- activeProfile: function () {
- return this.$store.getters.getActiveProfile
- },
- locale: function () {
- return this.$i18n.locale
- },
- activeSubscriptions: function () {
- const subscriptions = deepCopy(this.activeProfile.subscriptions)
-
- subscriptions.forEach(channel => {
- // Change thumbnail size to 35x35, as that's the size we display it
- // so we don't need to download a bigger image (the default is 176x176)
- channel.thumbnail = channel.thumbnail?.replace(/=s\d+/, '=s35')
- })
-
- subscriptions.sort((a, b) => {
- return a.name?.toLowerCase().localeCompare(b.name?.toLowerCase(), this.locale)
- })
-
- if (this.backendPreference === 'invidious') {
- subscriptions.forEach((channel) => {
- channel.thumbnail = youtubeImageUrlToInvidious(channel.thumbnail, this.currentInvidiousInstanceUrl)
- })
- }
-
- return subscriptions
- },
- hidePopularVideos: function () {
- return this.$store.getters.getHidePopularVideos
- },
- hidePlaylists: function () {
- return this.$store.getters.getHidePlaylists
- },
- hideTrendingVideos: function () {
- return this.$store.getters.getHideTrendingVideos
- },
- hideActiveSubscriptions: function () {
- return this.$store.getters.getHideActiveSubscriptions
- },
- hideLabelsSideBar: function () {
- return this.$store.getters.getHideLabelsSideBar
- },
- hideText: function () {
- return !this.isOpen && this.hideLabelsSideBar
- },
- applyNavIconExpand: function() {
- return {
- navIconExpand: this.hideText
- }
- },
- applyHiddenLabels: function() {
- return {
- hiddenLabels: this.hideText
- }
- },
- historyTitle: function() {
- const shortcut = process.platform === 'darwin'
- ? KeyboardShortcuts.APP.GENERAL.NAVIGATE_TO_HISTORY_MAC
- : KeyboardShortcuts.APP.GENERAL.NAVIGATE_TO_HISTORY
-
- return localizeAndAddKeyboardShortcutToActionTitle(
- this.$t('History.History'),
- shortcut
- )
- },
- settingsTitle: function() {
- return localizeAndAddKeyboardShortcutToActionTitle(
- this.$t('Settings.Settings'),
- KeyboardShortcuts.APP.GENERAL.NAVIGATE_TO_SETTINGS
- )
- }
- }
-})
diff --git a/src/renderer/components/sponsor-block-settings/sponsor-block-settings.js b/src/renderer/components/sponsor-block-settings/sponsor-block-settings.js
index 1425b84ab0961..2917131b72551 100644
--- a/src/renderer/components/sponsor-block-settings/sponsor-block-settings.js
+++ b/src/renderer/components/sponsor-block-settings/sponsor-block-settings.js
@@ -1,6 +1,6 @@
import { defineComponent } from 'vue'
import { mapActions } from 'vuex'
-import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue'
+import FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
import FtInput from '../ft-input/ft-input.vue'
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
diff --git a/src/renderer/components/subscription-settings/subscription-settings.css b/src/renderer/components/subscription-settings/subscription-settings.css
new file mode 100644
index 0000000000000..a4ffb52b032a4
--- /dev/null
+++ b/src/renderer/components/subscription-settings/subscription-settings.css
@@ -0,0 +1,4 @@
+.onlyShowLatestFromChannelNumber {
+ inline-size: calc(100% - 44px);
+ padding-inline-start: 44px;
+}
diff --git a/src/renderer/components/subscription-settings/subscription-settings.js b/src/renderer/components/subscription-settings/subscription-settings.js
index 231658a1f0126..9d455bbf6b2ce 100644
--- a/src/renderer/components/subscription-settings/subscription-settings.js
+++ b/src/renderer/components/subscription-settings/subscription-settings.js
@@ -1,13 +1,15 @@
import { defineComponent } from 'vue'
import { mapActions } from 'vuex'
-import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue'
+import FtSettingsSection from '../FtSettingsSection/FtSettingsSection.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
+import FtSlider from '../ft-slider/ft-slider.vue'
export default defineComponent({
name: 'SubscriptionSettings',
components: {
'ft-settings-section': FtSettingsSection,
- 'ft-toggle-switch': FtToggleSwitch
+ 'ft-toggle-switch': FtToggleSwitch,
+ 'ft-slider': FtSlider,
},
computed: {
hideWatchedSubs: function () {
@@ -16,6 +18,9 @@ export default defineComponent({
onlyShowLatestFromChannel: function () {
return this.$store.getters.getOnlyShowLatestFromChannel
},
+ onlyShowLatestFromChannelNumber: function () {
+ return this.$store.getters.getOnlyShowLatestFromChannelNumber
+ },
useRssFeeds: function () {
return this.$store.getters.getUseRssFeeds
},
@@ -32,6 +37,7 @@ export default defineComponent({
'updateUseRssFeeds',
'updateFetchSubscriptionsAutomatically',
'updateOnlyShowLatestFromChannel',
+ 'updateOnlyShowLatestFromChannelNumber',
'updateUnsubscriptionPopupStatus'
])
}
diff --git a/src/renderer/components/subscription-settings/subscription-settings.vue b/src/renderer/components/subscription-settings/subscription-settings.vue
index 9ae067ef5da55..906fc1aa4b9e9 100644
--- a/src/renderer/components/subscription-settings/subscription-settings.vue
+++ b/src/renderer/components/subscription-settings/subscription-settings.vue
@@ -18,6 +18,12 @@
:compact="true"
@change="updateUseRssFeeds"
/>
+
-
-
-
+
+
+
+
diff --git a/src/renderer/components/subscriptions-live/subscriptions-live.js b/src/renderer/components/subscriptions-live/subscriptions-live.js
index 2fcae92848f56..1a83a39785122 100644
--- a/src/renderer/components/subscriptions-live/subscriptions-live.js
+++ b/src/renderer/components/subscriptions-live/subscriptions-live.js
@@ -4,12 +4,11 @@ import SubscriptionsTabUI from '../subscriptions-tab-ui/subscriptions-tab-ui.vue
import {
getChannelPlaylistId,
- setPublishedTimestampsInvidious,
copyToClipboard,
getRelativeTimeFromDate,
showToast
} from '../../helpers/utils'
-import { invidiousAPICall, invidiousFetch } from '../../helpers/api/invidious'
+import { getInvidiousChannelLive, invidiousFetch } from '../../helpers/api/invidious'
import { getLocalChannelLiveStreams } from '../../helpers/api/local'
import { parseYouTubeRSSFeed, updateVideoListAfterProcessing } from '../../helpers/subscriptions'
@@ -338,17 +337,8 @@ export default defineComponent({
getChannelLiveInvidious: function (channel, failedAttempts = 0) {
return new Promise((resolve, reject) => {
- const subscriptionsPayload = {
- resource: 'channels',
- id: channel.id,
- subResource: 'streams',
- params: {}
- }
-
- invidiousAPICall(subscriptionsPayload).then((result) => {
- const videos = result.videos.filter(e => e.type === 'video')
-
- setPublishedTimestampsInvidious(videos)
+ getInvidiousChannelLive(channel.id).then((result) => {
+ const videos = result.videos
let name
diff --git a/src/renderer/components/subscriptions-videos/subscriptions-videos.js b/src/renderer/components/subscriptions-videos/subscriptions-videos.js
index 2c4e4eb6d23d1..87050f1b88148 100644
--- a/src/renderer/components/subscriptions-videos/subscriptions-videos.js
+++ b/src/renderer/components/subscriptions-videos/subscriptions-videos.js
@@ -3,13 +3,12 @@ import { mapActions, mapMutations } from 'vuex'
import SubscriptionsTabUI from '../subscriptions-tab-ui/subscriptions-tab-ui.vue'
import {
- setPublishedTimestampsInvidious,
copyToClipboard,
getRelativeTimeFromDate,
showToast,
getChannelPlaylistId
} from '../../helpers/utils'
-import { invidiousAPICall, invidiousFetch } from '../../helpers/api/invidious'
+import { getInvidiousChannelVideos, invidiousFetch } from '../../helpers/api/invidious'
import { getLocalChannelVideos } from '../../helpers/api/local'
import { parseYouTubeRSSFeed, updateVideoListAfterProcessing } from '../../helpers/subscriptions'
@@ -342,16 +341,7 @@ export default defineComponent({
getChannelVideosInvidiousScraper: function (channel, failedAttempts = 0) {
return new Promise((resolve, reject) => {
- const subscriptionsPayload = {
- resource: 'channels',
- id: channel.id,
- subResource: 'videos',
- params: {}
- }
-
- invidiousAPICall(subscriptionsPayload).then((result) => {
- setPublishedTimestampsInvidious(result.videos)
-
+ getInvidiousChannelVideos(channel.id).then((result) => {
let name
if (result.videos.length > 0) {
diff --git a/src/renderer/components/top-nav/top-nav.js b/src/renderer/components/top-nav/top-nav.js
index ddd3b2609361a..cf580cba750c6 100644
--- a/src/renderer/components/top-nav/top-nav.js
+++ b/src/renderer/components/top-nav/top-nav.js
@@ -9,7 +9,7 @@ import { IpcChannels, KeyboardShortcuts, MOBILE_WIDTH_THRESHOLD } from '../../..
import { localizeAndAddKeyboardShortcutToActionTitle, openInternalPath } from '../../helpers/utils'
import { translateWindowTitle } from '../../helpers/strings'
import { clearLocalSearchSuggestionsSession, getLocalSearchSuggestions } from '../../helpers/api/local'
-import { invidiousAPICall } from '../../helpers/api/invidious'
+import { getInvidiousSearchSuggestions } from '../../helpers/api/invidious'
const NAV_HISTORY_DISPLAY_LIMIT = 15
const HALF_OF_NAV_HISTORY_DISPLAY_LIMIT = Math.floor(NAV_HISTORY_DISPLAY_LIMIT / 2)
@@ -326,15 +326,7 @@ export default defineComponent({
return
}
- const searchPayload = {
- resource: 'search/suggestions',
- id: '',
- params: {
- q: query
- }
- }
-
- invidiousAPICall(searchPayload).then((results) => {
+ getInvidiousSearchSuggestions(query).then((results) => {
this.searchSuggestionsDataList = results.suggestions
}).catch((err) => {
console.error(err)
diff --git a/src/renderer/components/watch-video-live-chat/watch-video-live-chat.css b/src/renderer/components/watch-video-live-chat/watch-video-live-chat.css
index 307ed79a68bee..3cf66a8ddf110 100644
--- a/src/renderer/components/watch-video-live-chat/watch-video-live-chat.css
+++ b/src/renderer/components/watch-video-live-chat/watch-video-live-chat.css
@@ -34,6 +34,7 @@
color: var(--tertiary-text-color);
padding: 0;
margin: 0;
+ word-break: break-word;
}
:deep(.liveChatEmoji) {
diff --git a/src/renderer/components/watch-video-playlist/watch-video-playlist.js b/src/renderer/components/watch-video-playlist/watch-video-playlist.js
index bfe449b6eb0ec..e0d424bad8b62 100644
--- a/src/renderer/components/watch-video-playlist/watch-video-playlist.js
+++ b/src/renderer/components/watch-video-playlist/watch-video-playlist.js
@@ -3,7 +3,7 @@ import { mapMutations } from 'vuex'
import FtLoader from '../ft-loader/ft-loader.vue'
import FtCard from '../ft-card/ft-card.vue'
import FtListVideoNumbered from '../ft-list-video-numbered/ft-list-video-numbered.vue'
-import { copyToClipboard, setPublishedTimestampsInvidious, showToast } from '../../helpers/utils'
+import { copyToClipboard, showToast } from '../../helpers/utils'
import {
getLocalPlaylist,
parseLocalPlaylistVideo,
@@ -471,7 +471,6 @@ export default defineComponent({
this.channelName = result.author
this.channelId = result.authorId
- setPublishedTimestampsInvidious(result.videos)
this.playlistItems = this.playlistItems.concat(result.videos)
this.isLoading = false
diff --git a/src/renderer/helpers/api/invidious.js b/src/renderer/helpers/api/invidious.js
index 063eaca4103db..8afd29172b7b3 100644
--- a/src/renderer/helpers/api/invidious.js
+++ b/src/renderer/helpers/api/invidious.js
@@ -38,7 +38,7 @@ export function invidiousFetch(url) {
}
}
-export function invidiousAPICall({ resource, id = '', params = {}, doLogError = true, subResource = '' }) {
+function invidiousAPICall({ resource, id = '', params = {}, doLogError = true, subResource = '' }) {
return new Promise((resolve, reject) => {
const requestUrl = getCurrentInstanceUrl() + '/api/v1/' + resource + '/' + id + (!isNullOrEmpty(subResource) ? `/${subResource}` : '') + '?' + new URLSearchParams(params).toString()
invidiousFetch(requestUrl)
@@ -100,11 +100,135 @@ export async function invidiousGetChannelInfo(channelId) {
})
}
-export async function invidiousGetPlaylistInfo(playlistId) {
+/**
+ * @param {string} tab
+ * @param {string} channelId
+ * @param {string | undefined | null} continuation
+ * @param {string | undefined} sortBy
+ */
+async function getInvidiousChannelTab(tab, channelId, continuation, sortBy) {
+ const params = {}
+
+ if (continuation) {
+ params.continuation = continuation
+ }
+
+ if (sortBy) {
+ params.sort_by = sortBy
+ }
+
return await invidiousAPICall({
+ resource: 'channels',
+ id: channelId,
+ subResource: tab,
+ params
+ })
+}
+
+/**
+ * @param {string} channelId
+ * @param {string | undefined} sortBy
+ * @param {string | undefined | null} continuation
+ */
+export async function getInvidiousChannelVideos(channelId, sortBy, continuation) {
+ const response = await getInvidiousChannelTab('videos', channelId, continuation, sortBy)
+
+ setMultiplePublishedTimestamps(response.videos)
+
+ return response
+}
+
+/**
+ * @param {string} channelId
+ * @param {string | undefined} sortBy
+ * @param {string | undefined | null} continuation
+ */
+export async function getInvidiousChannelShorts(channelId, sortBy, continuation) {
+ const response = await getInvidiousChannelTab('shorts', channelId, continuation, sortBy)
+
+ // workaround for Invidious sending incorrect information
+ // https://github.com/iv-org/invidious/issues/3801
+ response.videos.forEach(video => {
+ video.isUpcoming = false
+ delete video.published
+ delete video.premiereTimestamp
+ })
+
+ return response
+}
+
+/**
+ * @param {string} channelId
+ * @param {string | undefined} sortBy
+ * @param {string | undefined | null} continuation
+ */
+export async function getInvidiousChannelLive(channelId, sortBy, continuation) {
+ const response = await getInvidiousChannelTab('streams', channelId, continuation, sortBy)
+
+ setMultiplePublishedTimestamps(response.videos)
+
+ return response
+}
+
+/**
+ * @param {string} channelId
+ * @param {string | undefined} sortBy
+ * @param {string | undefined | null} continuation
+ */
+export async function getInvidiousChannelPlaylists(channelId, sortBy, continuation) {
+ return await getInvidiousChannelTab('playlists', channelId, continuation, sortBy)
+}
+
+/**
+ * @param {string} channelId
+ * @param {string | undefined | null} continuation
+ */
+export async function getInvidiousChannelReleases(channelId, continuation) {
+ return await getInvidiousChannelTab('releases', channelId, continuation)
+}
+
+/**
+ * @param {string} channelId
+ * @param {string | undefined | null} continuation
+ */
+export async function getInvidiousChannelPodcasts(channelId, continuation) {
+ return await getInvidiousChannelTab('podcasts', channelId, continuation)
+}
+
+/**
+ * @param {string} channelId
+ * @param {string} query
+ * @param {number} page
+ */
+export async function searchInvidiousChannel(channelId, query, page) {
+ const response = await invidiousAPICall({
+ resource: 'channels',
+ id: channelId,
+ subResource: 'search',
+ params: {
+ q: query,
+ page
+ }
+ })
+
+ response.forEach((item) => {
+ if (item.type === 'video') {
+ setPublishedTimestamp(item)
+ }
+ })
+
+ return response
+}
+
+export async function invidiousGetPlaylistInfo(playlistId) {
+ const playlist = await invidiousAPICall({
resource: 'playlists',
id: playlistId,
})
+
+ setMultiplePublishedTimestamps(playlist.videos)
+
+ return playlist
}
export async function invidiousGetVideoInformation(videoId) {
@@ -142,6 +266,118 @@ export async function invidiousGetCommentReplies({ id, replyToken }) {
return { commentData: parseInvidiousCommentData(response), continuation: response.continuation ?? null }
}
+/**
+ * @param {string} query
+ * @returns {Promise}
+ */
+export async function getInvidiousSearchSuggestions(query) {
+ return await invidiousAPICall({
+ resource: 'search/suggestions',
+ id: '',
+ params: {
+ q: query
+ }
+ })
+}
+
+/**
+ * @returns {Promise}
+ */
+export async function getInvidiousPopularFeed() {
+ const response = await invidiousAPICall({
+ resource: 'popular',
+ id: '',
+ params: {}
+ })
+
+ const items = response.filter((item) => {
+ return item.type === 'video' || item.type === 'shortVideo' || item.type === 'channel' || item.type === 'playlist'
+ })
+
+ items.forEach((item) => {
+ if (item.type === 'video' || item.type === 'shortVideo') {
+ setPublishedTimestamp(item)
+ }
+ })
+
+ return items
+}
+
+/**
+ * @param {'default' | 'music' | 'gaming' | 'movies'} tab
+ * @param {string} region
+ * @returns {Promise}
+ */
+export async function getInvidiousTrending(tab, region) {
+ const params = {
+ resource: 'trending',
+ id: '',
+ params: {
+ region
+ }
+ }
+
+ if (tab !== 'default') {
+ params.params.type = tab.charAt(0).toUpperCase() + tab.substring(1)
+ }
+
+ const response = await invidiousAPICall(params)
+
+ if (!response) {
+ return null
+ }
+
+ const items = response.filter((item) => {
+ return item.type === 'video' || item.type === 'channel' || item.type === 'playlist'
+ })
+
+ items.forEach((item) => {
+ if (item.type === 'video') {
+ setPublishedTimestamp(item)
+ }
+ })
+
+ return items
+}
+
+/**
+ * @param {string} query
+ * @param {number} page
+ * @param {any} searchSettings
+ * @returns {Promise}
+ */
+export async function getInvidiousSearchResults(query, page, searchSettings) {
+ let results = await invidiousAPICall({
+ resource: 'search',
+ id: '',
+ params: {
+ q: query,
+ page,
+ sort_by: searchSettings.sortBy,
+ date: searchSettings.time,
+ duration: searchSettings.duration,
+ type: searchSettings.type,
+ features: searchSettings.features.join(',')
+ }
+ })
+
+ if (!results) {
+ return null
+ }
+
+ results = results.filter((item) => {
+ return item.type === 'video' || item.type === 'channel' || item.type === 'playlist' || item.type === 'hashtag'
+ })
+
+ results.forEach((item) => {
+ if (item.type === 'video') {
+ setPublishedTimestamp(item)
+ }
+ })
+
+ return results
+}
+
/**
* @param {string} url
* @param {string?} currentInstance
@@ -377,14 +613,16 @@ function parseInvidiousCommunityAttachments(data) {
}
export async function getHashtagInvidious(hashtag, page = 1) {
- const payload = {
+ const response = await invidiousAPICall({
resource: 'hashtag',
id: hashtag,
params: {
page
}
- }
- const response = await invidiousAPICall(payload)
+ })
+
+ setMultiplePublishedTimestamps(response.results)
+
return response.results
}
@@ -476,3 +714,33 @@ export function mapInvidiousLegacyFormat(format) {
url: format.url
}
}
+
+/**
+ * @param {{
+ * liveNow: boolean,
+ * isUpcoming: boolean,
+ * premiereTimestamp: number,
+ * published: number
+ * }[]} videos
+ */
+function setMultiplePublishedTimestamps(videos) {
+ videos.forEach(setPublishedTimestamp)
+}
+
+/**
+ * @param {{
+ * liveNow: boolean,
+ * isUpcoming: boolean,
+ * premiereTimestamp: number,
+ * published: number
+ * }} video
+ */
+function setPublishedTimestamp(video) {
+ if (video.liveNow) {
+ video.published = new Date().getTime()
+ } else if (video.isUpcoming) {
+ video.published = video.premiereTimestamp * 1000
+ } else if (typeof video.published === 'number') {
+ video.published *= 1000
+ }
+}
diff --git a/src/renderer/helpers/api/local.js b/src/renderer/helpers/api/local.js
index a332273a8ea15..9b1e3b07ac991 100644
--- a/src/renderer/helpers/api/local.js
+++ b/src/renderer/helpers/api/local.js
@@ -658,6 +658,8 @@ export function parseLocalChannelHeader(channel, onlyIdNameThumbnail = false) {
const image = header.content.image
thumbnailUrl = image.avatar?.image[0].url
}
+ } else if (header.content.animated_image) {
+ thumbnailUrl = header.content.animated_image.image[0].url
}
if (!thumbnailUrl && channel.metadata.thumbnail) {
@@ -859,6 +861,7 @@ function handleSearchResponse(response) {
return item.type === 'Video' || item.type === 'Channel' || item.type === 'Playlist' || item.type === 'HashtagTile' || item.type === 'Movie' || item.type === 'LockupView'
})
.map((item) => parseListItem(item))
+ .filter((item) => item)
return {
results,
@@ -1130,7 +1133,7 @@ export function parseLocalListVideo(item) {
author: video.author.name,
authorId: video.author.id,
description: video.description,
- viewCount: isNaN(video.view_count) ? (video.short_view_count.text == null ? null : parseLocalSubscriberCount(video.short_view_count.text)) : extractNumberFromString(video.view_count.text),
+ viewCount: video.view_count?.text == null ? (video.short_view_count.text == null ? null : parseLocalSubscriberCount(video.short_view_count.text)) : extractNumberFromString(video.view_count.text),
published,
lengthSeconds: isNaN(video.duration.seconds) ? '' : video.duration.seconds,
liveNow: video.is_live,
@@ -1160,6 +1163,14 @@ function parseLockupView(lockupView, channelId = undefined, channelName = undefi
const thumbnailOverlayBadgeView = lockupView.content_image.primary_thumbnail.overlays
.find(overlay => overlay.is(YTNodes.ThumbnailOverlayBadgeView))
+ const playlistId = lockupView.content_id
+
+ // Filter out mixes without playlist pages (we don't support watch page-only mixes)
+ // https://wiki.archiveteam.org/index.php/YouTube/Technical_details#Playlists
+ if (playlistId.startsWith('RD') && !playlistId.startsWith('RDCL')) {
+ return null
+ }
+
const maybeChannelText = lockupView.metadata?.metadata?.metadata_rows?.[0]?.metadata_parts?.[0]?.text
if (maybeChannelText && maybeChannelText.endpoint?.metadata.page_type === 'WEB_PAGE_TYPE_CHANNEL') {
@@ -1170,7 +1181,7 @@ function parseLockupView(lockupView, channelId = undefined, channelName = undefi
return {
type: 'playlist',
dataSource: 'local',
- playlistId: lockupView.content_id,
+ playlistId,
title: lockupView.metadata.title.text,
thumbnail: lockupView.content_image.primary_thumbnail.image[0].url,
channelName,
@@ -1180,6 +1191,7 @@ function parseLockupView(lockupView, channelId = undefined, channelName = undefi
}
default:
console.warn(`Unknown lockup content type: ${lockupView.content_type}`, lockupView)
+ return null
}
}
@@ -1493,7 +1505,7 @@ export function mapLocalLegacyFormat(format) {
}
/**
- * @param {import('youtubei.js').YTNodes.Comment|import('youtubei.js').YTNodes.CommentView} comment
+ * @param {import('youtubei.js').YTNodes.CommentView} comment
* @param {import('youtubei.js').YTNodes.CommentThread} commentThread
*/
export function parseLocalComment(comment, commentThread = undefined) {
@@ -1507,7 +1519,7 @@ export function parseLocalComment(comment, commentThread = undefined) {
hasReplyToken = true
}
- const parsed = {
+ return {
id: comment.comment_id,
dataType: 'local',
authorLink: comment.author.id,
@@ -1524,33 +1536,11 @@ export function parseLocalComment(comment, commentThread = undefined) {
replyToken,
showReplies: false,
replies: [],
-
- // default values for the properties set below
- memberIconUrl: '',
- time: '',
- likes: 0,
- numReplies: 0
+ memberIconUrl: comment.is_member ? comment.member_badge.url : '',
+ time: getRelativeTimeFromDate(calculatePublishedDate(comment.published_time.replace('(edited)', '').trim()), false),
+ likes: comment.like_count,
+ numReplies: parseLocalSubscriberCount(comment.reply_count)
}
-
- 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 = getRelativeTimeFromDate(calculatePublishedDate(comment_.published.text.replace('(edited)', '').trim()), false)
- 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 = getRelativeTimeFromDate(calculatePublishedDate(commentView.published_time.replace('(edited)', '').trim()), false)
- parsed.likes = commentView.like_count
- parsed.numReplies = parseLocalSubscriberCount(commentView.reply_count)
- }
-
- return parsed
}
/**
diff --git a/src/renderer/helpers/subscriptions.js b/src/renderer/helpers/subscriptions.js
index 41afe8c061ba3..50e422d643ab6 100644
--- a/src/renderer/helpers/subscriptions.js
+++ b/src/renderer/helpers/subscriptions.js
@@ -42,13 +42,22 @@ export function updateVideoListAfterProcessing(videos) {
// ordered last to show first eligible video from channel
// if the first one incidentally failed one of the above checks
if (store.getters.getOnlyShowLatestFromChannel) {
- const authors = new Set()
+ const authors = new Map()
videoList = videoList.filter((video) => {
if (!video.authorId) {
return true
- } else if (!authors.has(video.authorId)) {
- authors.add(video.authorId)
+ }
+
+ if (!authors.has(video.authorId)) {
+ authors.set(video.authorId, 1)
return true
+ } else {
+ const currentVideos = authors.get(video.authorId)
+
+ if (currentVideos < store.getters.getOnlyShowLatestFromChannelNumber) {
+ authors.set(video.authorId, currentVideos + 1)
+ return true
+ }
}
return false
diff --git a/src/renderer/helpers/utils.js b/src/renderer/helpers/utils.js
index 71391650c03aa..0739a6e0122c3 100644
--- a/src/renderer/helpers/utils.js
+++ b/src/renderer/helpers/utils.js
@@ -1,5 +1,3 @@
-import fs from 'fs/promises'
-
import { IpcChannels } from '../../constants'
import FtToastEvents from '../components/ft-toast/ft-toast-events'
import i18n from '../i18n/index'
@@ -100,26 +98,6 @@ export function calculatePublishedDate(publishedText, isLive = false, isUpcoming
return date.getTime() - timeSpan
}
-/**
- * @param {{
- * liveNow: boolean,
- * isUpcoming: boolean,
- * premiereTimestamp: number,
- * published: number
- * }[]} videos
- */
-export function setPublishedTimestampsInvidious(videos) {
- videos.forEach(video => {
- if (video.liveNow) {
- video.published = new Date().getTime()
- } else if (video.isUpcoming) {
- video.published = video.premiereTimestamp * 1000
- } else if (typeof video.published === 'number') {
- video.published *= 1000
- }
- })
-}
-
/**
* @param {import('youtubei.js/dist/src/parser/classes/PlayerStoryboardSpec').StoryboardData} storyboard
* @param {number} videoLengthSeconds
@@ -356,6 +334,85 @@ export async function readFileWithPicker(
}
}
+/**
+ * @param {string} fileName
+ * @param {string | Blob} content
+ * @param {string} fileTypeDescription
+ * @param {string} mimeType
+ * @param {string} fileExtension
+ * @param {string} [rememberDirectoryId]
+ * @param {'desktop' | 'documents' | 'downloads' | 'music' | 'pictures' | 'videos'} [startInDirectory]
+ * @returns {Promise}
+ */
+export async function writeFileWithPicker(
+ fileName,
+ content,
+ fileTypeDescription,
+ mimeType,
+ fileExtension,
+ rememberDirectoryId,
+ startInDirectory
+) {
+ // Only supported in Electron and desktop Chromium browsers
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/showOpenFilePicker#browser_compatibility
+ // As we know it is supported in Electron, adding the build flag means we can skip the runtime check in Electron
+ // and allow terser to remove the unused else block
+ if (process.env.IS_ELECTRON || 'showSaveFilePicker' in window) {
+ let writableFileStream
+
+ try {
+ /** @type {FileSystemFileHandle} */
+ const handle = await window.showSaveFilePicker({
+ suggestedName: fileName,
+ excludeAcceptAllOption: true,
+ multiple: false,
+ id: rememberDirectoryId,
+ startIn: startInDirectory,
+ types: [{
+ description: fileTypeDescription,
+ accept: {
+ [mimeType]: [fileExtension]
+ }
+ }],
+ })
+
+ writableFileStream = await handle.createWritable()
+ await writableFileStream.write(content)
+ } catch (error) {
+ // user pressed cancel in the file picker
+ if (error.name === 'AbortError') {
+ return false
+ }
+
+ throw error
+ } finally {
+ if (writableFileStream) {
+ await writableFileStream.close()
+ }
+ }
+
+ return true
+ } else {
+ if (typeof content === 'string') {
+ content = new Blob([content], { type: mimeType })
+ }
+
+ const url = URL.createObjectURL(content)
+
+ const downloadLink = document.createElement('a')
+ downloadLink.setAttribute('download', encodeURIComponent(fileName))
+ downloadLink.setAttribute('href', url)
+ downloadLink.click()
+
+ // Small timeout to give the browser time to react to the click on the link
+ setTimeout(() => {
+ URL.revokeObjectURL(url)
+ }, 1000)
+
+ return true
+ }
+}
+
/**
* @param {{defaultPath: string, filters: {name: string, extensions: string[]}[]}} options
* @returns { Promise | {canceled: boolean?, filePath: string } | { canceled: boolean?, handle?: Promise }}
@@ -386,34 +443,6 @@ export async function showSaveDialog (options) {
}
}
-/**
- * Write to a file picked out from the `showSaveDialog` picker
- * @param {object} response the response from `showSaveDialog`
- * @param {string} content the content to be written to the file selected by the dialog
- */
-export async function writeFileFromDialog (response, content) {
- if (process.env.IS_ELECTRON) {
- const { filePath } = response
- return await fs.writeFile(filePath, content)
- } else {
- if ('showOpenFilePicker' in window) {
- const { handle } = response
- const writableStream = await handle.createWritable()
- await writableStream.write(content)
- await writableStream.close()
- } else {
- // If the native filesystem api is not available,
- const { filePath } = response
- const filename = filePath.split('/').at(-1)
- const a = document.createElement('a')
- const url = URL.createObjectURL(new Blob([content], { type: 'application/octet-stream' }))
- a.setAttribute('href', url)
- a.setAttribute('download', encodeURI(filename))
- a.click()
- }
- }
-}
-
/**
* This creates an absolute web url from a given path.
* It will assume all given paths are relative to the current window location.
diff --git a/src/renderer/store/modules/settings.js b/src/renderer/store/modules/settings.js
index 6704450a948a1..eb241922fd512 100644
--- a/src/renderer/store/modules/settings.js
+++ b/src/renderer/store/modules/settings.js
@@ -172,6 +172,7 @@ const state = {
baseTheme: 'system',
mainColor: 'Red',
secColor: 'Blue',
+ defaultAutoplayInterruptionIntervalHours: 3,
defaultCaptionSettings: '{}',
defaultInterval: 5,
defaultPlayback: 1,
@@ -233,6 +234,7 @@ const state = {
listType: 'grid',
maxVideoPlaybackRate: 3,
onlyShowLatestFromChannel: false,
+ onlyShowLatestFromChannelNumber: 1,
openDeepLinksInNewWindow: false,
playNextVideo: false,
proxyHostname: '127.0.0.1',
diff --git a/src/renderer/views/Channel/Channel.js b/src/renderer/views/Channel/Channel.js
index 500d23901d495..ccdb36d3827c4 100644
--- a/src/renderer/views/Channel/Channel.js
+++ b/src/renderer/views/Channel/Channel.js
@@ -13,7 +13,6 @@ import ChannelHome from '../../components/ChannelHome/ChannelHome.vue'
import autolinker from 'autolinker'
import {
- setPublishedTimestampsInvidious,
copyToClipboard,
extractNumberFromString,
showToast,
@@ -23,10 +22,16 @@ import {
import { isNullOrEmpty } from '../../helpers/strings'
import packageDetails from '../../../../package.json'
import {
- invidiousAPICall,
+ getInvidiousChannelLive,
+ getInvidiousChannelPlaylists,
+ getInvidiousChannelPodcasts,
+ getInvidiousChannelReleases,
+ getInvidiousChannelShorts,
+ getInvidiousChannelVideos,
invidiousGetChannelId,
invidiousGetChannelInfo,
invidiousGetCommunityPosts,
+ searchInvidiousChannel,
youtubeImageUrlToInvidious
} from '../../helpers/api/invidious'
import {
@@ -1147,32 +1152,18 @@ export default defineComponent({
},
channelInvidiousVideos: function (sortByChanged) {
- const payload = {
- resource: 'channels',
- id: this.id,
- subResource: 'videos',
- params: {
- sort_by: this.videoSortBy,
- }
- }
-
if (sortByChanged) {
this.videoContinuationData = null
}
let more = false
if (this.videoContinuationData) {
- payload.params.continuation = this.videoContinuationData
more = true
- }
-
- if (!more) {
+ } else {
this.isElementListLoading = true
}
- invidiousAPICall(payload).then((response) => {
- setPublishedTimestampsInvidious(response.videos)
-
+ getInvidiousChannelVideos(this.id, this.videoSortBy, this.videoContinuationData).then((response) => {
if (more) {
this.latestVideos = this.latestVideos.concat(response.videos)
} else {
@@ -1199,38 +1190,18 @@ export default defineComponent({
},
channelInvidiousShorts: function (sortByChanged) {
- const payload = {
- resource: 'channels',
- id: this.id,
- subResource: 'shorts',
- params: {
- sort_by: this.shortSortBy,
- }
- }
-
if (sortByChanged) {
this.shortContinuationData = null
}
let more = false
if (this.shortContinuationData) {
- payload.params.continuation = this.shortContinuationData
more = true
- }
-
- if (!more) {
+ } else {
this.isElementListLoading = true
}
- invidiousAPICall(payload).then((response) => {
- // workaround for Invidious sending incorrect information
- // https://github.com/iv-org/invidious/issues/3801
- response.videos.forEach(video => {
- video.isUpcoming = false
- delete video.published
- delete video.premiereTimestamp
- })
-
+ getInvidiousChannelShorts(this.id, this.shortSortBy, this.shortContinuationData).then((response) => {
if (more) {
this.latestShorts.push(...response.videos)
} else {
@@ -1259,32 +1230,18 @@ export default defineComponent({
},
channelInvidiousLive: function (sortByChanged) {
- const payload = {
- resource: 'channels',
- id: this.id,
- subResource: 'streams',
- params: {
- sort_by: this.liveSortBy,
- }
- }
-
if (sortByChanged) {
this.liveContinuationData = null
}
let more = false
if (this.liveContinuationData) {
- payload.params.continuation = this.liveContinuationData
more = true
- }
-
- if (!more) {
+ } else {
this.isElementListLoading = true
}
- invidiousAPICall(payload).then((response) => {
- setPublishedTimestampsInvidious(response.videos)
-
+ getInvidiousChannelLive(this.id, this.liveSortBy, this.liveContinuationData).then((response) => {
if (more) {
this.latestLive.push(...response.videos)
} else {
@@ -1389,16 +1346,8 @@ export default defineComponent({
getPlaylistsInvidious: function () {
this.isElementListLoading = true
- const payload = {
- resource: 'channels',
- subResource: 'playlists',
- id: this.id,
- params: {
- sort_by: this.playlistSortBy
- }
- }
- invidiousAPICall(payload).then((response) => {
+ getInvidiousChannelPlaylists(this.id, this.playlistSortBy).then((response) => {
this.playlistContinuationData = response.continuation || null
this.latestPlaylists = response.playlists
this.isElementListLoading = false
@@ -1426,20 +1375,7 @@ export default defineComponent({
return
}
- const payload = {
- resource: 'channels',
- subResource: 'playlists',
- id: this.id,
- params: {
- sort_by: this.playlistSortBy
- }
- }
-
- if (this.playlistContinuationData) {
- payload.params.continuation = this.playlistContinuationData
- }
-
- invidiousAPICall(payload).then((response) => {
+ getInvidiousChannelPlaylists(this.id, this.playlistSortBy, this.playlistContinuationData).then((response) => {
this.playlistContinuationData = response.continuation || null
this.latestPlaylists = this.latestPlaylists.concat(response.playlists)
this.isElementListLoading = false
@@ -1534,13 +1470,8 @@ export default defineComponent({
channelInvidiousReleases: function() {
this.isElementListLoading = true
- const payload = {
- resource: 'channels',
- subResource: 'releases',
- id: this.id,
- }
- invidiousAPICall(payload).then((response) => {
+ getInvidiousChannelReleases(this.id).then((response) => {
this.releaseContinuationData = response.continuation || null
this.latestReleases = response.playlists
this.isElementListLoading = false
@@ -1564,17 +1495,11 @@ export default defineComponent({
channelInvidiousReleasesMore: function () {
if (this.releaseContinuationData === null) {
- console.warn('There are no more podcasts available for this channel')
+ console.warn('There are no more releases available for this channel')
return
}
- const payload = {
- resource: 'channels',
- subResource: 'releases',
- id: this.id
- }
-
- invidiousAPICall(payload).then((response) => {
+ getInvidiousChannelReleases(this.id, this.releaseContinuationData).then((response) => {
this.releaseContinuationData = response.continuation || null
this.latestReleases = this.latestReleases.concat(response.playlists)
this.isElementListLoading = false
@@ -1647,13 +1572,8 @@ export default defineComponent({
channelInvidiousPodcasts: function() {
this.isElementListLoading = true
- const payload = {
- resource: 'channels',
- subResource: 'podcasts',
- id: this.id,
- }
- invidiousAPICall(payload).then((response) => {
+ getInvidiousChannelPodcasts(this.id).then((response) => {
this.podcastContinuationData = response.continuation || null
this.latestPodcasts = response.playlists
this.isElementListLoading = false
@@ -1681,13 +1601,7 @@ export default defineComponent({
return
}
- const payload = {
- resource: 'channels',
- subResource: 'podcasts',
- id: this.id
- }
-
- invidiousAPICall(payload).then((response) => {
+ getInvidiousChannelPodcasts(this.id, this.podcastContinuationData).then((response) => {
this.podcastContinuationData = response.continuation || null
this.latestPodcasts = this.latestPodcasts.concat(response.playlists)
this.isElementListLoading = false
@@ -1992,18 +1906,7 @@ export default defineComponent({
},
searchChannelInvidious: function () {
- const payload = {
- resource: 'channels',
- id: this.id,
- subResource: 'search',
- params: {
- q: this.lastSearchQuery,
- page: this.searchPage
- }
- }
-
- invidiousAPICall(payload).then((response) => {
- setPublishedTimestampsInvidious(response.filter(item => item.type === 'video'))
+ searchInvidiousChannel(this.id, this.lastSearchQuery, this.searchPage).then((response) => {
if (this.hideChannelPlaylists) {
this.searchResults = this.searchResults.concat(response.filter(item => item.type !== 'playlist'))
} else {
diff --git a/src/renderer/views/Hashtag/Hashtag.vue b/src/renderer/views/Hashtag/Hashtag.vue
index f41dd7b27c21a..7de7ada063cf8 100644
--- a/src/renderer/views/Hashtag/Hashtag.vue
+++ b/src/renderer/views/Hashtag/Hashtag.vue
@@ -53,7 +53,7 @@ import store from '../../store/index'
import { useRoute } from 'vue-router/composables'
import packageDetails from '../../../../package.json'
import { getHashtagLocal, parseLocalListVideo } from '../../helpers/api/local'
-import { copyToClipboard, setPublishedTimestampsInvidious, showToast } from '../../helpers/utils'
+import { copyToClipboard, showToast } from '../../helpers/utils'
import { isNullOrEmpty } from '../../helpers/strings'
import { getHashtagInvidious } from '../../helpers/api/invidious'
import { useI18n } from '../../composables/use-i18n-polyfill'
@@ -118,7 +118,6 @@ async function getHashtag() {
async function getInvidiousHashtag(hashtagInRoute, page) {
try {
const fetchedVideos = await getHashtagInvidious(hashtagInRoute, page)
- setPublishedTimestampsInvidious(fetchedVideos)
hashtag.value = '#' + hashtagInRoute
isLoading.value = false
apiUsed.value = 'invidious'
diff --git a/src/renderer/views/Playlist/Playlist.js b/src/renderer/views/Playlist/Playlist.js
index 1a2404bd8b731..91ddd0c3e8843 100644
--- a/src/renderer/views/Playlist/Playlist.js
+++ b/src/renderer/views/Playlist/Playlist.js
@@ -18,7 +18,6 @@ import {
import {
extractNumberFromString,
getIconForSortPreference,
- setPublishedTimestampsInvidious,
showToast,
deepCopy,
} from '../../helpers/utils'
@@ -388,8 +387,6 @@ export default defineComponent({
const dateString = new Date(result.updated * 1000)
this.lastUpdated = dateString.toLocaleDateString(this.currentLocale, { year: 'numeric', month: 'short', day: 'numeric' })
- setPublishedTimestampsInvidious(result.videos)
-
this.playlistItems = result.videos
this.updatePageTitle()
diff --git a/src/renderer/views/Popular/Popular.vue b/src/renderer/views/Popular/Popular.vue
index edc14b6e7f56d..491a5a99e7c86 100644
--- a/src/renderer/views/Popular/Popular.vue
+++ b/src/renderer/views/Popular/Popular.vue
@@ -32,8 +32,8 @@ import FtElementList from '../../components/FtElementList/FtElementList.vue'
import FtRefreshWidget from '../../components/ft-refresh-widget/ft-refresh-widget.vue'
import store from '../../store/index'
-import { invidiousAPICall } from '../../helpers/api/invidious'
-import { copyToClipboard, getRelativeTimeFromDate, setPublishedTimestampsInvidious, showToast } from '../../helpers/utils'
+import { getInvidiousPopularFeed } from '../../helpers/api/invidious'
+import { copyToClipboard, getRelativeTimeFromDate, showToast } from '../../helpers/utils'
import { useI18n } from '../../composables/use-i18n-polyfill'
import { KeyboardShortcuts } from '../../../constants'
@@ -65,36 +65,22 @@ onBeforeUnmount(() => {
})
async function fetchPopularInfo() {
- const searchPayload = {
- resource: 'popular',
- id: '',
- params: {}
- }
-
isLoading.value = true
- const result = await invidiousAPICall(searchPayload)
- .catch((err) => {
- const errorMessage = t('Invidious API Error (Click to copy)')
- showToast(`${errorMessage}: ${err}`, 10000, () => {
- copyToClipboard(err)
- })
- return undefined
- })
- if (!result) {
+ try {
+ const items = await getInvidiousPopularFeed()
+
+ store.commit('setLastPopularRefreshTimestamp', new Date())
+ shownResults.value = items
isLoading.value = false
- return
+ store.commit('setPopularCache', items)
+ } catch (err) {
+ isLoading.value = false
+ const errorMessage = t('Invidious API Error (Click to copy)')
+ showToast(`${errorMessage}: ${err}`, 10000, () => {
+ copyToClipboard(err)
+ })
}
-
- const items = result.filter((item) => {
- return item.type === 'video' || item.type === 'shortVideo' || item.type === 'channel' || item.type === 'playlist'
- })
-
- setPublishedTimestampsInvidious(items.filter(item => item.type === 'video' || item.type === 'shortVideo'))
- store.commit('setLastPopularRefreshTimestamp', new Date())
- shownResults.value = items
- isLoading.value = false
- store.commit('setPopularCache', items)
}
/**
diff --git a/src/renderer/views/Search/Search.js b/src/renderer/views/Search/Search.js
index 472bf26605b9c..eb274ed5ad22e 100644
--- a/src/renderer/views/Search/Search.js
+++ b/src/renderer/views/Search/Search.js
@@ -7,11 +7,10 @@ import FtAutoLoadNextPageWrapper from '../../components/ft-auto-load-next-page-w
import {
copyToClipboard,
searchFiltersMatch,
- setPublishedTimestampsInvidious,
showToast,
} from '../../helpers/utils'
import { getLocalSearchContinuation, getLocalSearchResults } from '../../helpers/api/local'
-import { invidiousAPICall } from '../../helpers/api/invidious'
+import { getInvidiousSearchResults } from '../../helpers/api/invidious'
import packageDetails from '../../../../package.json'
import { SEARCH_CHAR_LIMIT } from '../../../constants'
@@ -225,37 +224,17 @@ export default defineComponent({
this.isLoading = true
}
- const searchPayload = {
- resource: 'search',
- id: '',
- params: {
- q: payload.query,
- page: this.searchPage,
- sort_by: payload.searchSettings.sortBy,
- date: payload.searchSettings.time,
- duration: payload.searchSettings.duration,
- type: payload.searchSettings.type,
- features: payload.searchSettings.features.join(',')
- }
- }
-
- invidiousAPICall(searchPayload).then((result) => {
- if (!result) {
+ getInvidiousSearchResults(payload.query, this.searchPage, payload.searchSettings).then((results) => {
+ if (!results) {
return
}
this.apiUsed = 'invidious'
- const returnData = result.filter((item) => {
- return item.type === 'video' || item.type === 'channel' || item.type === 'playlist' || item.type === 'hashtag'
- })
-
- setPublishedTimestampsInvidious(returnData.filter(item => item.type === 'video'))
-
if (this.searchPage !== 1) {
- this.shownResults = this.shownResults.concat(returnData)
+ this.shownResults = this.shownResults.concat(results)
} else {
- this.shownResults = returnData
+ this.shownResults = results
}
this.isLoading = false
@@ -272,7 +251,7 @@ export default defineComponent({
this.$store.commit('addToSessionSearchHistory', historyPayload)
- this.updateSubscriptionDetails(returnData)
+ this.updateSubscriptionDetails(results)
}).catch((err) => {
console.error(err)
const errorMessage = this.$t('Invidious API Error (Click to copy)')
diff --git a/src/renderer/views/Settings/Settings.js b/src/renderer/views/Settings/Settings.js
index 24d2b97637ff0..5d3d4c92f5c8c 100644
--- a/src/renderer/views/Settings/Settings.js
+++ b/src/renderer/views/Settings/Settings.js
@@ -16,7 +16,7 @@ import ExperimentalSettings from '../../components/ExperimentalSettings/Experime
import PasswordSettings from '../../components/PasswordSettings/PasswordSettings.vue'
import PasswordDialog from '../../components/PasswordDialog/PasswordDialog.vue'
import FtToggleSwitch from '../../components/ft-toggle-switch/ft-toggle-switch.vue'
-import FtSettingsMenu from '../../components/ft-settings-menu/ft-settings-menu.vue'
+import FtSettingsMenu from '../../components/FtSettingsMenu/FtSettingsMenu.vue'
const ACTIVE_CLASS_NAME = 'active'
const SETTINGS_MOBILE_WIDTH_THRESHOLD = 1015
diff --git a/src/renderer/views/Trending/Trending.js b/src/renderer/views/Trending/Trending.js
index 425bb9ffd7d19..915970dc7cb34 100644
--- a/src/renderer/views/Trending/Trending.js
+++ b/src/renderer/views/Trending/Trending.js
@@ -7,9 +7,9 @@ import FtIconButton from '../../components/ft-icon-button/ft-icon-button.vue'
import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
import FtRefreshWidget from '../../components/ft-refresh-widget/ft-refresh-widget.vue'
-import { copyToClipboard, getRelativeTimeFromDate, setPublishedTimestampsInvidious, showToast } from '../../helpers/utils'
+import { copyToClipboard, getRelativeTimeFromDate, showToast } from '../../helpers/utils'
import { getLocalTrending } from '../../helpers/api/local'
-import { invidiousAPICall } from '../../helpers/api/invidious'
+import { getInvidiousTrending } from '../../helpers/api/invidious'
import { KeyboardShortcuts } from '../../../constants'
export default defineComponent({
@@ -135,30 +135,14 @@ export default defineComponent({
getTrendingInfoInvidious: function () {
this.isLoading = true
- const trendingPayload = {
- resource: 'trending',
- id: '',
- params: { region: this.region }
- }
-
- if (this.currentTab !== 'default') {
- trendingPayload.params.type = this.currentTab.charAt(0).toUpperCase() + this.currentTab.slice(1)
- }
-
- invidiousAPICall(trendingPayload).then((result) => {
- if (!result) {
+ getInvidiousTrending(this.currentTab, this.region).then((items) => {
+ if (!items) {
return
}
- const returnData = result.filter((item) => {
- return item.type === 'video' || item.type === 'channel' || item.type === 'playlist'
- })
-
- setPublishedTimestampsInvidious(returnData.filter(item => item.type === 'video'))
-
- this.shownResults = returnData
+ this.shownResults = items
this.isLoading = false
- this.$store.commit('setTrendingCache', { value: returnData, page: this.currentTab })
+ this.$store.commit('setTrendingCache', { value: items, page: this.currentTab })
nextTick(() => {
this.$refs[this.currentTab]?.focus()
})
diff --git a/src/renderer/views/Watch/Watch.js b/src/renderer/views/Watch/Watch.js
index e9ff3c753a49e..040c616ddefe1 100644
--- a/src/renderer/views/Watch/Watch.js
+++ b/src/renderer/views/Watch/Watch.js
@@ -57,6 +57,8 @@ export default defineComponent({
beforeRouteLeave: async function (to, from, next) {
this.handleRouteChange()
window.removeEventListener('beforeunload', this.handleWatchProgress)
+ document.removeEventListener('keydown', this.resetAutoplayInterruptionTimeout)
+ document.removeEventListener('click', this.resetAutoplayInterruptionTimeout)
if (this.$refs.player) {
await this.$refs.player.destroyPlayer()
@@ -119,6 +121,8 @@ export default defineComponent({
playNextTimeout: null,
playNextCountDownIntervalId: null,
infoAreaSticky: true,
+ blockVideoAutoplay: false,
+ autoplayInterruptionTimeout: null,
onMountedRun: false,
@@ -160,6 +164,9 @@ export default defineComponent({
proxyVideos: function () {
return this.$store.getters.getProxyVideos
},
+ defaultAutoplayInterruptionIntervalHours: function () {
+ return this.$store.getters.getDefaultAutoplayInterruptionIntervalHours
+ },
defaultInterval: function () {
return this.$store.getters.getDefaultInterval
},
@@ -321,7 +328,13 @@ export default defineComponent({
this.getVideoInformationLocal()
}
+ document.removeEventListener('keydown', this.resetAutoplayInterruptionTimeout)
+ document.removeEventListener('click', this.resetAutoplayInterruptionTimeout)
+ document.addEventListener('keydown', this.resetAutoplayInterruptionTimeout)
+ document.addEventListener('click', this.resetAutoplayInterruptionTimeout)
+
window.addEventListener('beforeunload', this.handleWatchProgress)
+ this.resetAutoplayInterruptionTimeout()
},
changeTimestamp: function (timestamp) {
@@ -1233,6 +1246,18 @@ export default defineComponent({
return
}
+ if (this.blockVideoAutoplay) {
+ showToast(this.$t('Autoplay Interruption Timer',
+ this.defaultAutoplayInterruptionIntervalHours,
+ {
+ autoplayInterruptionIntervalHours: this.defaultAutoplayInterruptionIntervalHours
+ }),
+ 3_600_000
+ )
+ this.resetAutoplayInterruptionTimeout()
+ return
+ }
+
if (this.watchingPlaylist && this.getPlaylistPauseOnCurrent()) {
this.disablePlaylistPauseOnCurrent()
return
@@ -1639,6 +1664,12 @@ export default defineComponent({
this.updatePlaylistLastPlayedAt({ _id: playlist._id })
},
+ resetAutoplayInterruptionTimeout() {
+ clearTimeout(this.autoplayInterruptionTimeout)
+ this.autoplayInterruptionTimeout = setTimeout(() => { this.blockVideoAutoplay = true }, this.defaultAutoplayInterruptionIntervalHours * 3_600_000)
+ this.blockVideoAutoplay = false
+ },
+
...mapActions([
'setAppTitle',
'updateHistory',
diff --git a/static/locales/af.yaml b/static/locales/af.yaml
index 646bc8995b599..69f145fdb146c 100644
--- a/static/locales/af.yaml
+++ b/static/locales/af.yaml
@@ -452,7 +452,6 @@ Settings:
Hide Videos on Watch: ''
Fetch Feeds from RSS: ''
Fetch Automatically: ''
- Only Show Latest Video for Each Channel: ''
Confirm Before Unsubscribing: ''
Distraction Free Settings:
Distraction Free Settings: ''
@@ -632,17 +631,18 @@ Profile:
Create Profile Name: ''
Profile Name: ''
Color Picker: ''
- Custom Color: ''
- Profile Preview: ''
- Create Profile: ''
- Update Profile: ''
- Make Default Profile: ''
- Delete Profile: ''
- Are you sure you want to delete this profile?: ''
- All subscriptions will also be deleted.: ''
- Profile could not be found: ''
- Your profile name cannot be empty: ''
- Profile has been created: ''
+ Custom Color: 'Pasgemaakte kleur'
+ Profile Preview: 'Profielvoorskou'
+ Create Profile: 'Skep profiel'
+ Update Profile: 'Werk profiel by'
+ Make Default Profile: 'Maak verstekprofiel'
+ Delete Profile: 'Skrap profiel'
+ Are you sure you want to delete this profile?: 'Is u seker u wil hierdie profiel
+ skrap?'
+ All subscriptions will also be deleted.: 'Alle intekeninge sal ook geskrap word.'
+ Profile could not be found: 'Profiel kon nie gevind word nie'
+ Your profile name cannot be empty: 'U profielnaam kan nie leeg wees nie'
+ Profile has been created: 'Profiel is geskep'
Profile has been updated: 'Profiel is bygewerk'
Your default profile has been set to {profile}: 'U verstekprofiel is ingestel op
{profile}'
@@ -860,6 +860,9 @@ Video:
’n Google-aantekening en betaalde lidmaatskap op die oplaaier se kanaal vereis.
AgeRestricted: Video’s met ’n ouderdomsperk kan nie met FreeTube gekyk word nie
omdat dit ’n Google-aantekening en ouderdomvebestigde YouTube-rekening vereis.
+ DeArrow:
+ Show Original Details: Toon oorspronklike details
+ Show Modified Details: Toon gewysigde details
Videos:
#& Sort By
Sort By:
diff --git a/static/locales/ar.yaml b/static/locales/ar.yaml
index 4ca94fdfbd639..6ecad4ae9071a 100644
--- a/static/locales/ar.yaml
+++ b/static/locales/ar.yaml
@@ -446,7 +446,6 @@ Settings:
Hide Videos on Watch: 'أخفِ الفيديوهات عند مشاهدتها'
Fetch Feeds from RSS: 'جلب المحتوى عن طريق RSS'
Fetch Automatically: جلب الخلاصة تلقائيا
- Only Show Latest Video for Each Channel: عرض أحدث فيديو فقط لكل قناة
Confirm Before Unsubscribing: تجنب إلغاء الاشتراك عن طريق الخطأ
Data Settings:
diff --git a/static/locales/be.yaml b/static/locales/be.yaml
index 348966720271d..78f5f1a8dc80f 100644
--- a/static/locales/be.yaml
+++ b/static/locales/be.yaml
@@ -484,8 +484,6 @@ Settings:
Fetch Feeds from RSS: 'Атрымліваць стужкі з RSS'
Fetch Automatically: 'Аўтаматычна атрымліваць стужку'
Confirm Before Unsubscribing: Пацвердзіце перад тым як адпісацца
- Only Show Latest Video for Each Channel: Паказваць толькі апошняе відэа для кожнага
- канала
Distraction Free Settings:
Distraction Free Settings: 'Адцягненне ўвагі'
Sections:
@@ -1054,8 +1052,7 @@ Tooltips:
Ignore Warnings: 'Адключыць папярэджанні, калі бягучы вонкавы прайгравальнік не
падтрымлівае бягучае дзеянне (напрыклад, пераварочванне плэй-ліста і г.д.).'
Custom External Player Arguments: 'Любыя карыстальніцкія аргументы каманднага
- радка, якія вы хочаце перадаць вонкаваму
- прайгравальніку.'
+ радка, якія вы хочаце перадаць вонкаваму прайгравальніку.'
DefaultCustomArgumentsTemplate: "(Па змаўчанні: '{defaultCustomArguments}')"
Ignore Default Arguments: Не адпраўляйце ніякіх аргументаў па змаўчанні на вонкавы
прайгравальнік, акрамя URL-адраса відэа (напрыклад, частата прайгравання, URL-адрас
diff --git a/static/locales/bg.yaml b/static/locales/bg.yaml
index 6d7acd45c6109..8c3e8abb03701 100644
--- a/static/locales/bg.yaml
+++ b/static/locales/bg.yaml
@@ -475,8 +475,6 @@ Settings:
Hide Videos on Watch: 'Скриване на видеата при гледане'
Fetch Feeds from RSS: 'Извличане на съдържания през RSS'
Fetch Automatically: Автоматично извличане на съдържание
- Only Show Latest Video for Each Channel: Показване само най-новите видеа за всеки
- канал
Confirm Before Unsubscribing: Избягване на случайно отписване
Data Settings:
Data Settings: 'Данни'
@@ -1078,8 +1076,7 @@ Tooltips:
FreeTube ще отвори връзката в браузъра по подразбиране.\n"
External Player Settings:
Custom External Player Arguments: Всички персонализирани аргументи от командния
- ред, които искате да бъдат предадени на външния
- плейър.
+ ред, които искате да бъдат предадени на външния плейър.
Ignore Warnings: Премахване на предупрежденията, когато текущият външен плейър
не поддържа текущото действие (напр. обръщане на плейлисти и др.).
Custom External Player Executable: По подразбиране FreeTube предполага, че избраният
diff --git a/static/locales/br.yaml b/static/locales/br.yaml
index ebe209a0887f8..b3de25df2e8a6 100644
--- a/static/locales/br.yaml
+++ b/static/locales/br.yaml
@@ -1138,8 +1138,7 @@ Tooltips:
nemet URL ar video (d.s. feur lenn, URL ar roll-videoioù, etc.). Treuzkaset
e vo an arguzennoù personelaet.'
Custom External Player Arguments: 'An holl arguzennoù personelaet el linennoù
- urzhiañ, a faot deoc''h e vefe treuzkaset
- d''al lenner diavaez.'
+ urzhiañ, a faot deoc''h e vefe treuzkaset d''al lenner diavaez.'
DefaultCustomArgumentsTemplate: "(Dre ziouer : '{defaultCustomArguments}')"
Distraction Free Settings:
Hide Channels: 'Lakait ID ur chadenn evit mirout ouzh an holl videoioù, rolloù-videoioù
diff --git a/static/locales/cs.yaml b/static/locales/cs.yaml
index 81323ada09076..2460fd90593c4 100644
--- a/static/locales/cs.yaml
+++ b/static/locales/cs.yaml
@@ -424,7 +424,7 @@ Settings:
4k: '4k'
8k: '8k'
Playlist Next Video Interval: Interval pro další video na playlistu
- Next Video Interval: Další interval videa
+ Next Video Interval: Čas do automatického přehrání
Display Play Button In Video Player: Zobrazit tlačítko Přehrát v přehrávači videa
Scroll Volume Over Video Player: Měnit hlasitost posuvem kolečka myši na přehrávači
Fast-Forward / Rewind Interval: Interval rychlého přetáčení vpřed / vzad
@@ -449,6 +449,7 @@ Settings:
Folder Button: Vybrat složku
Enter Fullscreen on Display Rotate: Při otočení displeje přejít na celou obrazovku
Skip by Scrolling Over Video Player: Posouvat čas posuvem kolečka myši na přehrávači
+ Autoplay Interruption Timer: Čas přerušení automatického přehrávání
Privacy Settings:
Privacy Settings: 'Soukromí'
Remember History: 'Zapamatovat historii'
@@ -475,9 +476,10 @@ Settings:
Hide Videos on Watch: 'Skrýt přehraná videa'
Fetch Feeds from RSS: 'Získávat odběry z RSS'
Fetch Automatically: Automaticky načítat odběry
- Only Show Latest Video for Each Channel: U každého kanálu zobrazit pouze nejnovější
- video
Confirm Before Unsubscribing: Zamezit nechtěným odběrům
+ To: Do
+ 'Limit the number of videos displayed for each channel': Omezit počet videí zobrazených
+ u každého kanálu
Distraction Free Settings:
Distraction Free Settings: 'Rozptylování'
Hide Video Views: 'Skrýt počet přehrání videa'
@@ -1204,3 +1206,6 @@ Keys:
arrowup: Šipka nahoru
arrowright: Šipka vpravo
arrowleft: Šipka vlevo
+Right-click or hold to see history: Klikněte pravým pro zobrazení historie
+Autoplay Interruption Timer: Automatické přehrávání zrušeno kvůli {autoplayInterruptionIntervalHours}
+ hodinám nečinnosti
diff --git a/static/locales/cy.yaml b/static/locales/cy.yaml
index dd6ba93af9c5d..b889d41748964 100644
--- a/static/locales/cy.yaml
+++ b/static/locales/cy.yaml
@@ -506,8 +506,6 @@ Settings:
Hide Videos on Watch: 'Cuddio Fideos wrth Wylio'
Fetch Feeds from RSS: 'Nôl Llif RSS'
Fetch Automatically: 'Nôl Llif yn Awtomatig'
- Only Show Latest Video for Each Channel: 'Dangos dim ond Fideo Diweddaraf Pob
- Sianel'
Confirm Before Unsubscribing: Cadarnhau Cyn Dad-danysgrifio
Distraction Free Settings:
Distraction Free Settings: 'Dim Tarfu'
diff --git a/static/locales/da.yaml b/static/locales/da.yaml
index bc4f2f8c2e994..ea8a04b386a0e 100644
--- a/static/locales/da.yaml
+++ b/static/locales/da.yaml
@@ -397,7 +397,6 @@ Settings:
Subscription Settings: 'Abonnementsindstillinger'
Hide Videos on Watch: 'Skjul Videoer på Se'
Fetch Feeds from RSS: 'Hent Feeds fra RSS'
- Only Show Latest Video for Each Channel: Vis Kun Seneste Video for Hver Kanal
Fetch Automatically: Hent Feed Automatisk
Confirm Before Unsubscribing: Bekræft Før Afmelding
Data Settings:
diff --git a/static/locales/de-DE.yaml b/static/locales/de-DE.yaml
index 87c7d9e4c6ffe..5721d0859afe1 100644
--- a/static/locales/de-DE.yaml
+++ b/static/locales/de-DE.yaml
@@ -272,8 +272,8 @@ Settings:
Settings: Einstellungen
General Settings:
General Settings: Allgemein
- Fallback to Non-Preferred Backend on Failure: Zum nicht bevorzugten Backend System
- bei Fehlschlag zurückkehren
+ Fallback to Non-Preferred Backend on Failure: Bei Ausfall auf nicht bevorzugtes
+ Backend zurückgreifen
Enable Search Suggestions: Suchvorschläge aktivieren
Default Landing Page: Standard Startseite
@@ -317,8 +317,8 @@ Settings:
Auto Load Next Page:
Label: Nächste Seite automatisch laden
Tooltip: Zusätzliche Seiten und Kommentare automatisch laden.
- Open Deep Links In New Window: URLs die an FreeTube übergeben werden in einem
- neuen Fenster öffnen
+ Open Deep Links In New Window: An FreeTube übergebene URLs in einem neuen Fenster
+ öffnen
Theme Settings:
Theme Settings: Farbschema
Match Top Bar with Main Color: Obere Leiste an Hauptfarbe anpassen
@@ -429,7 +429,7 @@ Settings:
4k: 4k
8k: 8k
Playlist Next Video Interval: Zeit zwischen automatischer Videowiedergabe
- Next Video Interval: Intervall bis zum nächsten Video
+ Next Video Interval: Automatischer Wiedergabe-Timer
Display Play Button In Video Player: Wiedergabetaste im Videoabspieler anzeigen
Scroll Volume Over Video Player: Lautstärke durch Scrollen auf Video ändern
Fast-Forward / Rewind Interval: Intervall für schnelles Vor-/Zurückspulen
@@ -454,15 +454,17 @@ Settings:
Unterordner zu erstellen.
Enter Fullscreen on Display Rotate: Beim Drehen des Bildschirms zu Vollbild wechseln
Skip by Scrolling Over Video Player: Überspringen durch Scrollen über den Videoabspieler
+ Autoplay Interruption Timer: Automatische Wiedergabe Unterbrechungs-Timer
Subscription Settings:
Subscription Settings: Abo
Hide Videos on Watch: Videos bei Wiedergabe ausblenden
Fetch Feeds from RSS: Feeds von RSS abrufen
Fetch Automatically: Feed automatisch abrufen
- Only Show Latest Video for Each Channel: Nur das neueste Video für jeden Kanal
- anzeigen
Confirm Before Unsubscribing: Unbeabsichtigtes Deabonnieren verhindern
+ 'Limit the number of videos displayed for each channel': Die Anzahl der für jeden
+ Kanal angezeigten Videos begrenzen
+ To: Limitieren auf
Privacy Settings:
Watch history has been cleared: Wiedergabeverlauf wurde gelöscht
Are you sure you want to remove your entire watch history?: Bist du sicher, dass
@@ -626,7 +628,7 @@ Settings:
Do Nothing: Nichts tun
Category Color: Kategoriefarbe
UseDeArrowTitles: DeArrow-Videotitel verwenden
- UseDeArrowThumbnails: DeArrow für Thumbnails verwenden
+ UseDeArrowThumbnails: DeArrow für Miniaturansichten verwenden
'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': DeArrow
Thumbnail Generator API URL (Standard ist https://dearrow-thumb.ajay.app)
External Player Settings:
@@ -639,7 +641,7 @@ Settings:
Players:
None:
Name: Keine
- Ignore Default Arguments: Standardargument ignorieren
+ Ignore Default Arguments: Standardargumente ignorieren
Download Settings:
Download Settings: Herunterladen
Ask Download Path: Nach dem Herunterladepfad fragen
@@ -669,7 +671,7 @@ Settings:
Set Password To Prevent Access: Passwort festlegen, um den Zugriff auf die Einstellungen
zu verhindern
Set Password: Passwort festlegen
- Sort Settings Sections (A-Z): Die Einstellungen von A bis Z sortieren
+ Sort Settings Sections (A-Z): Einstellungsabschnitte sortieren (A-Z)
Return to Settings Menu: Zurück zum Einstellungsmenü
About:
#On About page
@@ -886,7 +888,7 @@ Video:
CodecsVideoAudioNoItags: 'Codecs: {videoCodec} / {audioCodec}'
You appear to be offline: Sie scheinen offline zu sein.
Playback will resume automatically when your connection comes back: Die Wiedergabe
- startet automatisch, sobald deine Verbindung wieder da ist.
+ wird automatisch fortgesetzt, wenn deine Verbindung wiederhergestellt ist.
Skipped segment: 'Segment {segmentCategory} übersprungen'
TranslatedCaptionTemplate: '{language} (übersetzt von {originalLanguage})'
Exit Full Window: Vollständiges Fenster beenden
@@ -1149,7 +1151,8 @@ Tooltips:
SponsorBlock Settings:
UseDeArrowTitles: Videotitel durch von Benutzern eingereichte Titel von DeArrow
ersetzen.
- UseDeArrowThumbnails: Video-Thumbnails durch Thumbnails von DeArrow ersetzen.
+ UseDeArrowThumbnails: Video-Miniaturansichten durch Miniaturansichten von DeArrow
+ ersetzen.
Playing Next Video Interval: Nächstes Video wird sofort abgespielt. Zum Abbrechen
klicken. | Nächstes Video wird in {nextVideoInterval} Sekunden abgespielt. Zum Abbrechen
klicken. | Nächstes Video wird in {nextVideoInterval} Sekunden abgespielt. Zum Abbrechen
@@ -1246,3 +1249,10 @@ Keys:
arrowright: Pfeil nach rechts
KeyboardShortcutTemplate: '{label} ({shortcut})'
shortcutJoinOperator: +
+Right-click or hold to see history: Mit der rechten Maustaste klicken oder halten,
+ um den Verlauf zu sehen
+Autoplay Interruption Timer: Automatische Wiedergabe wurde aufgrund von {autoplayInterruptionIntervalHours}
+ Stunden Inaktivität abgebrochen
+Description:
+ Collapse Description: Weniger anzeigen
+ Expand Description: '...mehr'
diff --git a/static/locales/el.yaml b/static/locales/el.yaml
index c82afa8ae7d84..5e57bc21595ce 100644
--- a/static/locales/el.yaml
+++ b/static/locales/el.yaml
@@ -315,8 +315,6 @@ Settings:
Hide Videos on Watch: 'Απόκρυψη των βίντεο κατά την αναπαραγωγή'
Fetch Feeds from RSS: 'Φόρτωση τροφοδοσίας RSS'
Fetch Automatically: Αυτόματη Λήψη Τροφοδοσίας
- Only Show Latest Video for Each Channel: Εμφάνιση μόνο του τελευταίου βίντεο για
- κάθε κανάλι
Data Settings:
Data Settings: 'Ρυθμίσεις Δεδομένων'
Select Import Type: 'Επιλογή Τρόπου Εισαγωγής'
@@ -879,8 +877,7 @@ Tooltips:
ρυθμίσεις δεν επηρεάζουν τις εξωτερικές συσκευές αναπαραγωγής.
DefaultCustomArgumentsTemplate: "(Προεπιλογή: '{defaultCustomArguments}')"
Custom External Player Arguments: Τυχόν προσαρμοσμένα ορίσματα γραμμής εντολών,
- που θέλετε να μεταβιβαστούν στο εξωτερικό
- πρόγραμμα αναπαραγωγής.
+ που θέλετε να μεταβιβαστούν στο εξωτερικό πρόγραμμα αναπαραγωγής.
Experimental Settings:
Replace HTTP Cache: Απενεργοποιεί το Electron's disk-based HTTP cache και ενεργοποιεί
μια προσαρμοσμένη προσωρινή μνήμη εικόνων στη μνήμη. Θα οδηγήσει σε αυξημένη
diff --git a/static/locales/en-GB.yaml b/static/locales/en-GB.yaml
index da691e5c040a8..b73d9867d62b8 100644
--- a/static/locales/en-GB.yaml
+++ b/static/locales/en-GB.yaml
@@ -479,7 +479,6 @@ Settings:
Hide Videos on Watch: 'Hide Videos on Watch'
Fetch Feeds from RSS: 'Fetch feeds from RSS'
Fetch Automatically: Fetch feed automatically
- Only Show Latest Video for Each Channel: Only show latest video for each channel
Confirm Before Unsubscribing: Confirm before unsubscribing
Data Settings:
Data Settings: 'Data'
@@ -1016,6 +1015,9 @@ Comments:
There are no comments available for this post: There are no comments available for
this post
Up Next: 'Up Next'
+Description:
+ Expand Description: ...more
+ Collapse Description: Show less
# Toast Messages
Local API Error (Click to copy): 'Local API Error (Click to copy)'
@@ -1200,3 +1202,4 @@ Keys:
arrowdown: Down Arrow
KeyboardShortcutTemplate: '{label} ({shortcut})'
shortcutJoinOperator: +
+Right-click or hold to see history: Right-click or hold to see history
diff --git a/static/locales/en-US.yaml b/static/locales/en-US.yaml
index 8c156dc213ce5..9df8f7a9112b8 100644
--- a/static/locales/en-US.yaml
+++ b/static/locales/en-US.yaml
@@ -416,7 +416,8 @@ Settings:
Skip by Scrolling Over Video Player: Skip by Scrolling Over Video Player
Display Play Button In Video Player: Display Play Button In Video Player
Enter Fullscreen on Display Rotate: Enter Fullscreen on Display Rotate
- Next Video Interval: Next Video Interval
+ Next Video Interval: Autoplay Countdown Timer
+ Autoplay Interruption Timer: Autoplay Interruption Timer
Fast-Forward / Rewind Interval: Fast-Forward / Rewind Interval
Default Volume: Default Volume
Default Playback Rate: Default Playback Rate
@@ -488,7 +489,8 @@ Settings:
Hide Videos on Watch: Hide Videos on Watch
Fetch Feeds from RSS: Fetch Feeds from RSS
Fetch Automatically: Fetch Feed Automatically
- Only Show Latest Video for Each Channel: Only Show Latest Video for Each Channel
+ 'Limit the number of videos displayed for each channel': 'Limit the number of videos displayed for each channel'
+ To: To
Confirm Before Unsubscribing: Confirm Before Unsubscribing
Distraction Free Settings:
Distraction Free Settings: Distraction Free
@@ -998,6 +1000,9 @@ Comments:
Hearted: Hearted
Up Next: Up Next
+Description:
+ Expand Description: ...more
+ Collapse Description: Show less
#Tooltips
Tooltips:
@@ -1080,6 +1085,7 @@ Playlist will not pause when current video is finished: Playlist will not pause
Playlist will pause when current video is finished: Playlist will pause when current video is finished
Playing Next Video Interval: Playing next video in no time. Click to cancel. | Playing next video in {nextVideoInterval} second. Click to cancel. | Playing next video in {nextVideoInterval} seconds. Click to cancel.
Canceled next video autoplay: Canceled next video autoplay
+Autoplay Interruption Timer: Autoplay canceled due to {autoplayInterruptionIntervalHours} hours of inactivity
Default Invidious instance has been set to {instance}: Default Invidious instance has been set to {instance}
Default Invidious instance has been cleared: Default Invidious instance has been cleared
diff --git a/static/locales/es-MX.yaml b/static/locales/es-MX.yaml
index 7481f62b1add0..0426058810b1b 100644
--- a/static/locales/es-MX.yaml
+++ b/static/locales/es-MX.yaml
@@ -635,7 +635,8 @@ Tooltips:
problema, FreeTube intentará usar automáticamente otra API como método de respaldo
al activar esta opción.
External Player Settings:
- Custom External Player Arguments: Cualquier argumento, que deseé anticipar al reproductor externo.
+ Custom External Player Arguments: Cualquier argumento, que deseé anticipar al
+ reproductor externo.
DefaultCustomArgumentsTemplate: "(Por defecto: '{defaultCustomArguments}')"
External Player: Elegir un reproductor externo mostrará un ícono, para abrir el
video (o lista, si es compatible) en el reproductor externo, sobre la miniatura
diff --git a/static/locales/es.yaml b/static/locales/es.yaml
index db649373978f9..0253d3ca37006 100644
--- a/static/locales/es.yaml
+++ b/static/locales/es.yaml
@@ -310,6 +310,7 @@ Settings:
Auto Load Next Page:
Label: Carga automática de la página siguiente
Tooltip: Cargar automáticamente páginas adicionales y comentarios.
+ Open Deep Links In New Window: Abrir URL pasadas a FreeTube en una nueva ventana
Theme Settings:
Theme Settings: 'Tema'
Match Top Bar with Main Color: 'Usar color principal para barra superior'
@@ -420,7 +421,7 @@ Settings:
4k: '4k'
8k: '8k'
Playlist Next Video Interval: Intervalo de Siguiente Video en Playlist
- Next Video Interval: Siguiente segmento de vídeo
+ Next Video Interval: Temporizador de cuenta atrás de reproducción automática
Display Play Button In Video Player: Mostrar el botón de reproducción sobre el
vídeo
Scroll Volume Over Video Player: Cambiar el volumen con la rueda del ratón sobre
@@ -449,6 +450,7 @@ Settings:
Enter Fullscreen on Display Rotate: Entrar en pantalla completa al girar la pantalla
Skip by Scrolling Over Video Player: Omitir al desplazarse sobre el reproductor
de vídeo
+ Autoplay Interruption Timer: Temporizador de interrupción de reproducción automática
Privacy Settings:
Privacy Settings: 'Privacidad'
Remember History: 'Recordar historial'
@@ -475,9 +477,10 @@ Settings:
Hide Videos on Watch: 'Ocultar vídeos vistos'
Fetch Feeds from RSS: 'Recuperar suministros desde RSS'
Fetch Automatically: Obtener los feed automáticamente
- Only Show Latest Video for Each Channel: Mostrar solo los últimos vídeos de cada
- canal
Confirm Before Unsubscribing: Evitar bajas accidentales
+ 'Limit the number of videos displayed for each channel': Limitar el número de
+ vídeos mostrados para cada canal
+ To: A
Data Settings:
Data Settings: 'Datos'
Select Import Type: 'Seleccionar tipo de importación'
@@ -555,17 +558,17 @@ Settings:
Display Titles Without Excessive Capitalisation: Mostrar títulos sin mayúsculas
ni signos de puntuación excesivos
Hide Featured Channels: Ocultar canales recomendados
- Hide Channel Playlists: Ocultar las listas de reproducción de los canales
- Hide Channel Community: Ocultar canales de la comunidad
- Hide Channel Shorts: Ocultar canales de shorts
+ Hide Channel Playlists: Ocultar la pestaña "Listas de reproducción" del canal
+ Hide Channel Community: Ocultar la pestaña "Comunidad" del canal
+ Hide Channel Shorts: Ocultar la pestaña "Vídeos cortos" del canal
Sections:
Side Bar: Barra lateral
Channel Page: Página del canal
Watch Page: Ver la página
General: General
Subscriptions Page: Página de suscripciones
- Hide Channel Releases: Ocultar las nuevas publicaciones de los canales
- Hide Channel Podcasts: Ocultar canales de podcasts
+ Hide Channel Releases: Ocultar la pestaña "Lanzamientos" del canal
+ Hide Channel Podcasts: Ocultar la pestaña "Podcasts" del canal
Hide Subscriptions Shorts: Ocultar las suscripciones para shorts
Hide Subscriptions Videos: Ocultar las suscripciones de los Vídeos
Hide Subscriptions Live: Ocultar las suscripciones de los directos
@@ -580,6 +583,7 @@ Settings:
Hide Videos and Playlists Containing Text: Ocultar vídeos y listas de reproducción
que contengan texto
Hide Videos and Playlists Containing Text Placeholder: Palabra, fragmento o frase
+ Hide Channel Home: Ocultar la pestaña "Inicio" del canal
The app needs to restart for changes to take effect. Restart and apply change?: ¿Quieres
reiniciar FreeTube ahora para aplicar los cambios?
Proxy Settings:
@@ -811,6 +815,9 @@ Channel:
Releases: Publicaciones
This channel does not currently have any releases: Este canal no tiene actualmente
ninguna publicación
+ Home:
+ Home: Inicio
+ View Playlist: Ver lista de reproducción
Video:
Mark As Watched: 'Marcar como visto'
Remove From History: 'Borrar del historial'
@@ -938,6 +945,9 @@ Video:
AgeRestricted: Los vídeos con restricciones de edad no se pueden ver con FreeTube
ya que requieren iniciar sesión en Google y usar una cuenta de YouTube verificada
por edad.
+ DeArrow:
+ Show Original Details: Mostrar detalles originales
+ Show Modified Details: Mostrar detalles modificados
Videos:
#& Sort By
Sort By:
@@ -1092,12 +1102,15 @@ 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"
+ Open Deep Links In New Window: Las URL que se pasan a FreeTube, por ejemplo mediante
+ la redirección de extensiones del navegador o argumentos de la línea de comandos,
+ se abren en una ventana nueva.
External Player Settings:
Custom External Player Executable: Por defecto, FreeTube buscará el reproductor
externo seleccionado mediante la variable de entorno PATH, de no encontrarlo,
podrás especificar una ruta personalizada aquí.
- Custom External Player Arguments: Depara cada argumento mediante un punto y coma
- (;) cada argumento será enviado al reproductor externo.
+ Custom External Player Arguments: Cualquier argumento personalizado de la línea
+ de comandos que desee pasar al reproductor externo.
Ignore Warnings: Ocultar advertencias por argumentos incompatibles con el reproductor
(ej. invertir listas de reproducción, etc.).
External Player: La elección de un reproductor externo mostrará un icono, para
@@ -1215,3 +1228,19 @@ Search Listing:
3D: 3D
'Blocked opening potentially unsafe URL': 'Bloqueada la apertura de la URL potencialmente
insegura: «{url}».'
+KeyboardShortcutTemplate: '{label} ({shortcut})'
+Right-click or hold to see history: Clic con el botón derecho del ratón o mantén presionado
+ para ver el historial
+shortcutJoinOperator: +
+Keys:
+ alt: Alt
+ ctrl: Ctrl
+ arrowdown: Flecha hacia abajo
+ arrowleft: Flecha hacia la izquierda
+ arrowright: Flecha hacía la derecha
+ arrowup: Flecha hacia arriba
+Autoplay Interruption Timer: Reproducción automática cancelada debido a {autoplayInterruptionIntervalHours}
+ horas de inactividad
+Description:
+ Expand Description: '...más'
+ Collapse Description: Mostrar menos
diff --git a/static/locales/et.yaml b/static/locales/et.yaml
index f3078a427e5f9..07cb64cd2b555 100644
--- a/static/locales/et.yaml
+++ b/static/locales/et.yaml
@@ -418,7 +418,7 @@ Settings:
1440p: '1440p'
4k: '4k'
8k: '8k'
- Next Video Interval: Viivitus järgmise video esitamisel
+ Next Video Interval: Viivituse taimer järgmise video esitamisel
Display Play Button In Video Player: Kuva videomängijas esitamise nuppu
Scroll Volume Over Video Player: Muuda helivaljust videovaate kohal kerides
Fast-Forward / Rewind Interval: Kiirkerimise välp
@@ -443,6 +443,7 @@ Settings:
Alamkaustade loomiseks võid kasutada ka „\“ või „/“.
Skip by Scrolling Over Video Player: Jäta vahele, kerides üle videopleieri
Enter Fullscreen on Display Rotate: Ekraani pööramisel ava täisekraanivaade
+ Autoplay Interruption Timer: Viivituse taimer järgmise video esitamise katkestamisel
Privacy Settings:
Privacy Settings: 'Privaatsus'
Remember History: 'Jäta ajalugu meelde'
@@ -470,8 +471,10 @@ Settings:
Hide Videos on Watch: 'Vaatamisel peida videod'
Fetch Feeds from RSS: 'Laadi RSS-uudisvood'
Fetch Automatically: Laadi tellimuste voog automaatselt
- Only Show Latest Video for Each Channel: Iga kanali puhul näita vaid viimast videot
Confirm Before Unsubscribing: Väldi ekslikku ja juhuslikku tellimusest loobumist
+ To: Kuni
+ 'Limit the number of videos displayed for each channel': Piira igas kanalis näidatavate
+ videote arvu
Data Settings:
Data Settings: 'Andmehaldus'
Select Import Type: 'Vali imporditava faili vorming'
@@ -924,6 +927,9 @@ Video:
AgeRestricted: Kuna vajalik on sisselogimine Google'i kontoga, kus vanus on kontrollitud,
siis vanusepiiranguga videoid ei saa FreeTube'is vaadata.
Unlisted: Registriväline
+ DeArrow:
+ Show Original Details: Näita algseid üksikasju
+ Show Modified Details: Näita muudetud üksikasju
Videos:
#& Sort By
Sort By:
@@ -1194,3 +1200,10 @@ Keys:
arrowleft: Nool vasakule
arrowright: Nool paremale
arrowdown: Nool alla
+Right-click or hold to see history: Ajaloo nägemiseks klõpsa parema hiireklahviga
+ ja hoia klahvi all
+Autoplay Interruption Timer: Automaatne esitamine katkes peale {autoplayInterruptionIntervalHours}
+ tundi jõudeolekut
+Description:
+ Expand Description: '...vaata lisaks'
+ Collapse Description: Näita vähem
diff --git a/static/locales/eu.yaml b/static/locales/eu.yaml
index 0141485b9662f..41b6ccc45bb80 100644
--- a/static/locales/eu.yaml
+++ b/static/locales/eu.yaml
@@ -429,7 +429,7 @@ Settings:
8k: '8k'
Fast-Forward / Rewind Interval: Aurrera / atzera egiteko tartea
Scroll Volume Over Video Player: Aldatu bolumena bideo erreproduzitzailean
- Next Video Interval: Hurrengo bideo tartea
+ Next Video Interval: Erreproduzitu automatikoki atzerako kontaketaren tenporizadorea
Screenshot:
Enable: Bidea eman pantaila argazkiei
Error:
@@ -452,6 +452,7 @@ Settings:
Video Playback Rate Interval: Bideo Erreprodukzio-tasa tartea
Skip by Scrolling Over Video Player: Saltatu bideo-erreproduzitzailean korrituz
Enter Fullscreen on Display Rotate: Sartu pantaila osoko pantaila biratu pantailan
+ Autoplay Interruption Timer: Erreprodukzio automatikoa eteteko tenporizadorea
Privacy Settings:
Privacy Settings: 'Pribatutasuna'
Remember History: 'Historikoa oroitu'
@@ -479,9 +480,10 @@ Settings:
Hide Videos on Watch: 'Ikusten ari zaren bideoa ezkutatu'
Fetch Feeds from RSS: 'RSS jarioak eskuratu'
Fetch Automatically: Eskuratu jarioa automatikoki
- Only Show Latest Video for Each Channel: Erakutsi soilik kanal bakoitzeko azken
- bideoa
Confirm Before Unsubscribing: Saihestu ustekabeko harpidetza kentzea
+ 'Limit the number of videos displayed for each channel': Mugatu kanal bakoitzeko
+ bistaratzen diren bideo kopurua
+ To: Hona
Distraction Free Settings:
Distraction Free Settings: 'Oharkabetasunik ez'
Hide Video Views: 'Bideoen ikustaldi kopurua ezkutatu'
@@ -939,6 +941,9 @@ Video:
hasi eta adinak egiaztatutako YouTube-ko kontu bat erabili behar delako.
IP block: YouTubek bideoak ikusteko zure IP helbidea blokeatu du. Mesedez, saiatu
VPN edo proxy desberdin batera aldatzen.
+ DeArrow:
+ Show Original Details: Erakutsi jatorrizko xehetasunak
+ Show Modified Details: Erakutsi aldatutako xehetasunak
Videos:
#& Sort By
Sort By:
@@ -1225,3 +1230,10 @@ Keys:
ctrl: Ctrl
shortcutJoinOperator: +
KeyboardShortcutTemplate: '{label} ({shortcut})'
+Right-click or hold to see history: Egin klik eskuineko botoiarekin edo mantendu sakatuta
+ historia ikusteko
+Autoplay Interruption Timer: Erreprodukzio automatikoa bertan behera utzi da {autoplayInterruptionIntervalHours}
+ orduz geldirik egon delako
+Description:
+ Collapse Description: Gutxiago erakutsi
+ Expand Description: '...gehiago'
diff --git a/static/locales/fi.yaml b/static/locales/fi.yaml
index bcad0c8893b32..5d7bf13ac9add 100644
--- a/static/locales/fi.yaml
+++ b/static/locales/fi.yaml
@@ -355,8 +355,6 @@ Settings:
Hide Videos on Watch: 'Piilota katsotut videot'
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
-
Privacy Settings:
Watch history has been cleared: Katseluhistoria poistettiin
Are you sure you want to remove your entire watch history?: Haluatko varmasti
diff --git a/static/locales/fr-FR.yaml b/static/locales/fr-FR.yaml
index 3d3506a8f1194..0d4ec9003db1f 100644
--- a/static/locales/fr-FR.yaml
+++ b/static/locales/fr-FR.yaml
@@ -433,7 +433,7 @@ Settings:
8k: '8k'
Playlist Next Video Interval: Intervalle de la prochaine vidéo dans la liste de
lecture
- Next Video Interval: Intervalle vidéo suivante
+ Next Video Interval: Minuteur de lecture automatique
Scroll Volume Over Video Player: Contrôler le niveau du volume avec la molette
au dessus du lecteur vidéo
Display Play Button In Video Player: Afficher le bouton de lecture dans le lecteur
@@ -461,15 +461,17 @@ Settings:
Folder Label: Dossier de capture d'écran
Enter Fullscreen on Display Rotate: Entrer en plein écran sur l'affichage Rotation
Skip by Scrolling Over Video Player: Sauter en faisant défiler le lecteur vidéo
+ Autoplay Interruption Timer: Minuteur d'arrêt de la lecture automatique
Subscription Settings:
Subscription Settings: 'Abonnements'
Hide Videos on Watch: 'Masquer les vidéos visionnées'
Fetch Feeds from RSS: Récupération de flux RSS
Fetch Automatically: Récupération automatique des flux
- Only Show Latest Video for Each Channel: Afficher uniquement la dernière vidéo
- pour chaque chaîne
Confirm Before Unsubscribing: Évitez les désabonnements accidentels
+ 'Limit the number of videos displayed for each channel': Limiter le nombre de
+ vidéos affichées pour chaque chaîne
+ To: Pour
Privacy Settings:
Privacy Settings: Confidentialité
Remember History: Enregistrer l'historique
@@ -1262,3 +1264,9 @@ Keys:
arrowup: Flèche haut
alt: Alt
KeyboardShortcutTemplate: '{label} ({shortcut})'
+Right-click or hold to see history: Clic droit ou maintenez pour voir l'historique
+Autoplay Interruption Timer: Lecture automatique annulée après {autoplayInterruptionIntervalHours}
+ heures d'inactivité
+Description:
+ Expand Description: '...plus'
+ Collapse Description: Montrer moins
diff --git a/static/locales/he.yaml b/static/locales/he.yaml
index 315ab01a39976..3ec3ef1fa3e04 100644
--- a/static/locales/he.yaml
+++ b/static/locales/he.yaml
@@ -297,6 +297,7 @@ Settings:
Auto Load Next Page:
Label: טעינת העמוד הבא אוטומטית
Tooltip: טען דפים ותגובות נוספים באופן אוטומטי.
+ Open Deep Links In New Window: פתיחת כתובות שהועברו ל־FreeTube בחלון חדש
Theme Settings:
Theme Settings: 'ערכת עיצוב'
Match Top Bar with Main Color: 'התאמת האזור העליון לצבע הראשי'
@@ -313,6 +314,8 @@ Settings:
Nordic: נורדית
Solarized Dark: חשוך זוהר
Solarized Light: בהיר זוהר
+ Gruvbox Dark: תיבת גרוב כהה
+ Gruvbox Light: תיבת גרוב בהירה
Main Color Theme:
Main Color Theme: 'צבע ראשי'
Red: 'אדום'
@@ -360,6 +363,16 @@ Settings:
Solarized Blue: כחול זוהר
Solarized Violet: ויולט מואר בשמש
Solarized Cyan: סולרייזד כחול-ירוק
+ Gruvbox Light Orange: תיבת גרוב כתומה בהירה
+ Gruvbox Dark Green: תיבת גרוב ירוקה כהה
+ Gruvbox Dark Purple: תיבת גרוב סגולה כהה
+ Gruvbox Light Purple: תיבת גרוב סגולה בהירה
+ Gruvbox Dark Blue: תיבת גרוב כחולה כהה
+ Gruvbox Light Red: תיבת גרוב אדומה בהירה
+ Gruvbox Dark Yellow: תיבת גרוב צהובה כהה
+ Gruvbox Dark Orange: תיבת גרוב כתומה כהה
+ Gruvbox Dark Aqua: תיבת גרוב מים כהים
+ Gruvbox Light Blue: תיבת גרוב כחולה בהירה
Secondary Color Theme: 'ערכת צבע משנית'
#* Main Color Theme
UI Scale: יחס גודל הממשק
@@ -395,7 +408,7 @@ Settings:
4k: '4k'
8k: '8k'
Playlist Next Video Interval: מרווח זמן לפני ניגון הסרטון הבא בפלייליסט
- Next Video Interval: משך הסרטון הבא
+ Next Video Interval: מתזמן ספירה לאחור של נגינה אוטומטית
Display Play Button In Video Player: הצגת כפתור הניגון בתוך נגן הווידאו
Scroll Volume Over Video Player: גלילה על הסרטון לשינוי עוצמת השמע
Scroll Playback Rate Over Video Player: גלילת מהירות הנגינה על גבי נגן הווידאו
@@ -445,7 +458,6 @@ Settings:
Fetch Feeds from RSS: 'ייבוא עדכונים בעזרת RSS'
Fetch Automatically: משיכת ערוץ העדכונים אוטומטית
Confirm Before Unsubscribing: אישור לפני ביטול מינוי
- Only Show Latest Video for Each Channel: להציג רק את הסרטון האחרון לכל ערוץ
Data Settings:
Data Settings: 'נתונים'
Select Import Type: 'נא לבחור את תסדיר הייבוא'
@@ -517,17 +529,17 @@ Settings:
Display Titles Without Excessive Capitalisation: הצג כותרות ללא אותיות גדולות
וסימני פיסוק מיותרים
Hide Featured Channels: הסתרת ערוצים מומלצים
- Hide Channel Playlists: הסתרת רשימת נגינה של ערוץ
- Hide Channel Community: הסתרת קהילת הערוץ
- Hide Channel Shorts: הסתרת ה־Shorts של הערוץ
+ Hide Channel Playlists: הסתרת לשונית „רשימות נגינה” של ערוץ
+ Hide Channel Community: הסתרת לשונית ה„קהילת” הערוץ
+ Hide Channel Shorts: הסתרת לשונית ה־„Shorts” של הערוץ
Sections:
Watch Page: עמוד הצפייה
Channel Page: עמוד ערוץ
Side Bar: סרגל צד
General: כללי
Subscriptions Page: עמוד מינויים
- Hide Channel Podcasts: הסתרת הסכתים של הערוץ
- Hide Channel Releases: הסתרת שחרורים של הערוץ
+ Hide Channel Podcasts: הסתרת לשונית ה„הסכתים” של הערוץ
+ Hide Channel Releases: הסתרת לשונית ה„שחרורים” של הערוץ
Hide Subscriptions Live: הסתרת שידורים חיים של המינויים
Hide Subscriptions Shorts: הסתרת Shorts של המינויים
Hide Subscriptions Videos: הסתרת סרטוני מינוי
@@ -540,8 +552,9 @@ Settings:
Hide Channels Already Exists: ID הערוץ כבר קיים
Hide Channels API Error: אירעה שגיאה באיחזור משתמש עם ה-ID שסופק. נא לבדוק שוב
אם ה-ID נכון.
- Hide Videos and Playlists Containing Text: הסתר סרטונים ורשימות שידורים המכילים
+ Hide Videos and Playlists Containing Text: הסתרת סרטונים ורשימות שידורים המכילים
טקסט
+ Hide Channel Home: הסתרת לשונית ה„בית” של הערוץ
The app needs to restart for changes to take effect. Restart and apply change?: צריך
להפעיל את היישומון מחדש כדי שהשינויים ייכנסו לתוקף. להפעיל מחדש ולהחיל את השינוי?
Proxy Settings:
@@ -758,6 +771,9 @@ Channel:
Releases:
Releases: שחרורים
This channel does not currently have any releases: בערוץ הזה אין שחרורים כרגע
+ Home:
+ Home: בית
+ View Playlist: הצגת רשימת נגינה
Video:
Mark As Watched: 'סימון כנצפה'
Remove From History: 'הסרה מהיסטוריית הצפייה'
@@ -879,6 +895,9 @@ Video:
AgeRestricted: אי אפשר לצפות בסרטונים שמוגבלים בגיל עם FreeTube כיוון שהם דורשים
כניסה עם Google ושימוש בחשבון YouTube עם גיל מאומת.
Unlisted: לא מופיע
+ DeArrow:
+ Show Modified Details: הצגת פרטים לאחר שינוי
+ Show Original Details: הצגת פרטים מקוריים
Videos:
#& Sort By
Sort By:
@@ -996,6 +1015,8 @@ Tooltips:
שלך.\n"
Region for Trending: מגמות אזוריות מאפשרות לך לבחור סרטונים חמים של איזו מדינה
שמעניין אותך לראות.
+ Open Deep Links In New Window: כתובות שמועברות ל־FreeTube, כגון העברת הרחבות דפדפן
+ או ארגומנטים בשורת הפקודה, תיפתחנה בחלון חדש.
Player Settings:
Proxy Videos Through Invidious: יתבצע חיבור ל־Invidious כדי להגיש סרטונים במקום
להתחבר ישירות ל־YouTube.
@@ -1024,8 +1045,8 @@ Tooltips:
על נגנים חיצוניים.
Custom External Player Executable: כברירת מחדל FreeTube יניח שהנגן החיצוני הנבחר
נגיש דרך משתנה הסביבה PATH. במקרה הצורך, ניתן להגדיר כאן נתיב משלך.
- Custom External Player Arguments: הארגומנטים משלך לשורת הפקודה שיועברו לנגן החיצוני,
- מופרדים בפסיקים (‚;’).
+ Custom External Player Arguments: ארגומנטים כלשהם משלך לשורת הפקודה להעברה הלאה
+ לנגן החיצוני.
Ignore Default Arguments: אל תשלח אף ארגומנט סטנדרטי לנגן החיצוני, מלבד כתובת
הסרטון (למשל, קצב הפלייבק, כתובת הרשימה, וכו'). ארגומנטים מותאמים ימשיכו להיות
מועברים.
@@ -1124,3 +1145,13 @@ Channel Unhidden: '{channel} הוסר ממסנן ערוצים'
Channel Hidden: '{channel} נוסף למסנן ערוצים'
Trimmed input must be at least N characters long: הקלט המקוצץ חייב להיות באורך של
לפחות תו אחד | הקלט המקוצץ חייב להיות באורך של לפחות {length} תווים
+Keys:
+ arrowright: חץ ימינה
+ arrowup: חץ למעלה
+ arrowdown: חץ למטה
+ arrowleft: חץ שמאלה
+ ctrl: Ctrl
+ alt: Alt
+Right-click or hold to see history: לחיצה ימנית או החזקה כדי לראות היסטוריה
+shortcutJoinOperator: +
+KeyboardShortcutTemplate: '{label} ({shortcut})'
diff --git a/static/locales/hr.yaml b/static/locales/hr.yaml
index 9e3a1f1993b9b..b55df64ea13e7 100644
--- a/static/locales/hr.yaml
+++ b/static/locales/hr.yaml
@@ -449,8 +449,6 @@ Settings:
Hide Videos on Watch: 'Sakrij video nakon gledanja'
Fetch Feeds from RSS: 'Dohvati feedove s RSS-a'
Fetch Automatically: Automatski dohvati feed
- Only Show Latest Video for Each Channel: Prikaži samo najnoviji video za svaki
- kanal
Confirm Before Unsubscribing: Izbjegni slučajno otkazivanje pretplate
Data Settings:
diff --git a/static/locales/hu.yaml b/static/locales/hu.yaml
index 86bf225ea64ce..26b4e1f42290c 100644
--- a/static/locales/hu.yaml
+++ b/static/locales/hu.yaml
@@ -429,7 +429,7 @@ Settings:
4k: '4K'
8k: '8K'
Playlist Next Video Interval: Lejátszási lista következő videó intervalluma
- Next Video Interval: Következő videó időköze
+ Next Video Interval: Automatikus lejátszás időköze
Scroll Volume Over Video Player: A hangerő szintjét a videolejátszó feletti kerékkel
szabályozhatja
Display Play Button In Video Player: Lejátszás gomb megjelenítése a videolejátszóban
@@ -456,6 +456,7 @@ Settings:
Video Playback Rate Interval: Videó lejátszási sebesség léptetési köze
Enter Fullscreen on Display Rotate: Teljes képernyős mód a kijelzőn forgatáshoz
Skip by Scrolling Over Video Player: Kihagyás a Videolejátszó felett görgetve
+ Autoplay Interruption Timer: Automatikus lejátszás megszakításának időköze
Privacy Settings:
Privacy Settings: 'Adatvédelem'
Remember History: 'Előzmények megjegyzése'
@@ -482,9 +483,10 @@ Settings:
Hide Videos on Watch: 'Videók elrejtése megtekintés után'
Fetch Feeds from RSS: 'RSS-hírcsatornák beolvasása'
Fetch Automatically: Hírcsatorna automatikus lekérdezése
- Only Show Latest Video for Each Channel: Csak a legújabb videókat jelenítse meg
- a csatornáktól
Confirm Before Unsubscribing: Kerülje el a véletlen leiratkozást
+ 'Limit the number of videos displayed for each channel': Az egyes csatornákon
+ megjelenített videók számának korlátozása
+ To: 'Ennyire'
Data Settings:
Data Settings: 'Adat'
Select Import Type: 'Importálási típus kiválasztása'
@@ -1230,3 +1232,10 @@ Keys:
arrowright: Jobbra nyíl
KeyboardShortcutTemplate: '{label} ({shortcut})'
shortcutJoinOperator: +
+Right-click or hold to see history: Kattintson a jobb gombbal vagy tartsa lenyomva
+ az előzmények megtekintéséhez
+Autoplay Interruption Timer: Az automatikus lejátszás {autoplayInterruptionIntervalHours}
+ óra inaktivitás miatt visszavonásra került
+Description:
+ Collapse Description: Kevesebb megjelenítése
+ Expand Description: …továbbiak
diff --git a/static/locales/id.yaml b/static/locales/id.yaml
index c9a2a0d6839c1..5a0eb5fee527e 100644
--- a/static/locales/id.yaml
+++ b/static/locales/id.yaml
@@ -347,8 +347,6 @@ Settings:
Hide Videos on Watch: 'Sembunyikan Video saat Menonton'
Fetch Feeds from RSS: 'Ambil Umpan dari RSS'
Fetch Automatically: Ambil Umpan Secara Otomatis
- Only Show Latest Video for Each Channel: Hanya Tampilkan Video Terbaru untuk Setiap
- Kanal
Data Settings:
Data Settings: 'Pengaturan Data'
Select Import Type: 'Pilih Tipe Impor'
@@ -849,8 +847,8 @@ Tooltips:
dibuka di FreeTube, diklik.\nSecara default FreeTube akan membuka tautan yang
diklik dengan browser default Anda.\n"
External Player Settings:
- Custom External Player Arguments: Semua argumen perintah khusus,
- yang Anda ingin gunakan dengan pemutar eksternal.
+ Custom External Player Arguments: Semua argumen perintah khusus, yang Anda ingin
+ gunakan dengan pemutar eksternal.
Ignore Warnings: Jangan tampilkan peringatan saat pemutar eksternal saat ini tidak
mendukung tindakan yang ada (mis. membalik urutan daftar putar, dsb.).
Custom External Player Executable: Secara bawaan, FreeTube akan berasumsi bahwa
diff --git a/static/locales/is.yaml b/static/locales/is.yaml
index 991a962a67e2f..5eb67e2cc397a 100644
--- a/static/locales/is.yaml
+++ b/static/locales/is.yaml
@@ -425,7 +425,7 @@ Settings:
1440p: '1440p'
4k: '4k'
8k: '8k'
- Next Video Interval: Bil í næsta myndskeið
+ Next Video Interval: Niðurtalning í sjálfvirka spilun
Display Play Button In Video Player: Birta afspilunarhnapp í myndspilara
Scroll Volume Over Video Player: Skruna hljóðstyrk ofan á myndspilara
Fast-Forward / Rewind Interval: Millibil hraðspólunar / spóla til baka
@@ -450,6 +450,7 @@ Settings:
File Name Label: Mynstur skráaheita
Enter Fullscreen on Display Rotate: Fara í skjáfylli við snúning á skjá
Skip by Scrolling Over Video Player: Sleppa með því að skruna ofan á myndspilara
+ Autoplay Interruption Timer: Niðurtalning í stöðvun á sjálfvirkri spilun
Privacy Settings:
Privacy Settings: 'Gagnaleynd'
Remember History: 'Muna áhorfsferil'
@@ -477,9 +478,10 @@ Settings:
Hide Videos on Watch: 'Fela myndskeið eftir áhorf'
Fetch Feeds from RSS: 'Ná í streymi úr RSS'
Fetch Automatically: Sækja streymi sjálfvirkt
- Only Show Latest Video for Each Channel: Aðeins birta nýjasta myndskeið fyrir
- hverja myndskeiðarás
Confirm Before Unsubscribing: Staðfesta uppsögn áskriftar
+ To: Við
+ 'Limit the number of videos displayed for each channel': Takmarka fjölda myndskeiða
+ sem birt eru fyrir hverja rás
Distraction Free Settings:
Distraction Free Settings: 'Truflanaminnkandi'
Hide Video Views: 'Fela fjölda áhorfa á myndskeið'
@@ -508,12 +510,12 @@ Settings:
Watch Page: Áhorfssíða
General: Almennt
Subscriptions Page: Áskriftasíða
- Hide Channel Shorts: Fela stuttmyndir rása
- Hide Channel Playlists: Fela spilunarlista rása
- Hide Channel Community: Fela samfélag rása
+ Hide Channel Shorts: Fela stuttmyndaflipa rása
+ Hide Channel Playlists: Fela spilunarlistaflipa rása
+ Hide Channel Community: Fela samfélagsflipa rása
Hide Featured Channels: Fela rásir í deiglunni
- Hide Channel Podcasts: Fela hlaðvörp rása
- Hide Channel Releases: Fela útgáfur rása
+ Hide Channel Podcasts: Fela hlaðvarpsflipa rása
+ Hide Channel Releases: Fela útgáfuflipa rása
Hide Subscriptions Shorts: Fela stuttmyndir áskrifta
Hide Subscriptions Live: Fela bein streymi áskrifta
Hide Subscriptions Videos: Fela myndskeið áskrifta
@@ -529,6 +531,7 @@ Settings:
Hide Videos and Playlists Containing Text: Fela myndskeið og spilunarlista sem
innihalda texta
Hide Videos and Playlists Containing Text Placeholder: Orð, orðhluti eða setning
+ Hide Channel Home: Fela "Heim"-flipa rása
Data Settings:
Data Settings: 'Gögn'
Select Import Type: 'Veldu tegund innflutnings'
@@ -804,6 +807,9 @@ Channel:
Podcasts: Hlaðvörp
This channel does not currently have any podcasts: Þessi rás er ekki með nein
hlaðvörp í augnablikinu
+ Home:
+ Home: Heim
+ View Playlist: Skoða spilunarlista
Video:
Mark As Watched: 'Merkja sem búið að horfa á'
Remove From History: 'Fjarlægja úr áhorfsferli'
@@ -931,6 +937,9 @@ Video:
sem þau krefjast innskráningar á Google og notkunar á aldursvottuðum YouTube-reikningi.
IP block: YouTube hefur útilokað IP-vistfang þitt frá því að horfa á myndskeið.
Prófaðu að skipta yfir á annan VPN eða milliþjón.
+ DeArrow:
+ Show Original Details: Birta upprunalegar nánari upplýsingar
+ Show Modified Details: Birta breyttar nánari upplýsingar
Videos:
#& Sort By
Sort By:
@@ -1062,8 +1071,8 @@ Tooltips:
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ð.
External Player Settings:
- Custom External Player Arguments: Öll sérsniðin skipanaviðföng og rofar,
- sem beina á til utanaðkomandi spilarans.
+ Custom External Player Arguments: Öll sérsniðin skipanaviðföng og rofar, sem beina
+ á til utanaðkomandi spilarans.
Ignore Warnings: Hunsa aðvarinir þegar valinn utanaðkomandi spilari styður ekki
viðkomandi aðgerð (t.d. að snúa við spilunarlista, o.s.frv.).
Custom External Player Executable: Sjálfgefið gengur FreeTube út frá því að valinn
@@ -1202,3 +1211,18 @@ Search Listing:
360 Video: 360°
New: Nýtt
3D: 3D
+Keys:
+ arrowright: Hægri-ör
+ arrowleft: Vinstri-ör
+ alt: Alt
+ ctrl: Ctrl
+ arrowdown: Niður-ör
+ arrowup: Upp-ör
+Right-click or hold to see history: Hægri-smelltu til að sjá feril
+KeyboardShortcutTemplate: '{label} ({shortcut})'
+shortcutJoinOperator: +
+Autoplay Interruption Timer: Hætt sjálfvirkri spilun vegna {autoplayInterruptionIntervalHours}
+ klst án aðgerða
+Description:
+ Expand Description: '...meira'
+ Collapse Description: Birta minna
diff --git a/static/locales/it.yaml b/static/locales/it.yaml
index e6e1ba22e6cb2..c02243fc152d1 100644
--- a/static/locales/it.yaml
+++ b/static/locales/it.yaml
@@ -168,7 +168,7 @@ User Playlists:
Playlist {playlistName} has been deleted.: La playlist {playlistName} è stata
eliminata.
Some videos in the playlist are not loaded yet. Click here to copy anyway.: Alcuni
- video nella playlist non sono ancora stati caricati. Clicca qui per copiare
+ video nella playlist non sono ancora stati caricati. Fai clic qui per copiare
comunque.
This playlist does not exist: Questa playlist non esiste
Playlist name cannot be empty. Please input a name.: Il nome della playlist
@@ -309,6 +309,7 @@ Settings:
Auto Load Next Page:
Label: Carica automaticamente la pagina successiva
Tooltip: Carica automaticamente pagine e commenti aggiuntivi.
+ Open Deep Links In New Window: Apri URL passati a FreeTube in una nuova finestra
Theme Settings:
Theme Settings: 'Tema'
Match Top Bar with Main Color: 'Abbina la barra superiore al colore principale'
@@ -420,7 +421,7 @@ Settings:
8k: '8k'
Playlist Next Video Interval: Intervallo video successivo nella playlist
Fast-Forward / Rewind Interval: Avanzamento veloce o riavvolgimento video
- Next Video Interval: Prossimo intervallo video
+ Next Video Interval: Timer di conto alla rovescia per la riproduzione automatica
Display Play Button In Video Player: Visualizza il pulsante di riproduzione nel
lettore video
Scroll Volume Over Video Player: Controlla il volume scorrendo sul lettore video
@@ -445,6 +446,7 @@ Settings:
del video 3 cifre. %i ID video. Puoi anche usare \ o / per creare sottocartelle.
Enter Fullscreen on Display Rotate: Entra a schermo intero su Ruota schermo
Skip by Scrolling Over Video Player: Salta tramite scorrimento sul lettore video
+ Autoplay Interruption Timer: Timer di interruzione della riproduzione automatica
Privacy Settings:
Privacy Settings: 'Privacy'
Remember History: 'Salva la cronologia'
@@ -472,10 +474,11 @@ Settings:
Hide Videos on Watch: 'Nascondi i video visualizzati'
Fetch Feeds from RSS: Scarica gli aggiornamenti dai flussi RSS
Fetch Automatically: Recupera i feed automaticamente
- Only Show Latest Video for Each Channel: Mostra solo il video più recente per
- ciascun canale
Confirm Before Unsubscribing: Evita la cancellazione accidentale dell'iscrizione
+ 'Limit the number of videos displayed for each channel': Limita il numero di video
+ visualizzati per ogni canale
+ To: A
Data Settings:
How do I import my subscriptions?: Come posso importare le mie iscrizioni?
Unknown data key: Chiave dati sconosciuta
@@ -596,7 +599,7 @@ Settings:
Ip: Ip
Your Info: Le tue informazioni
Test Proxy: Testa proxy
- Clicking on Test Proxy will send a request to: Cliccando su Testa proxy verrà
+ Clicking on Test Proxy will send a request to: Facendo clic su Testa proxy verrà
inviata una richiesta a
Proxy Port Number: Numero di porta del proxy
Proxy Host: Host del proxy
@@ -894,6 +897,9 @@ Video:
AgeRestricted: I video con limiti di età non possono essere guardati con FreeTube
poiché richiedono l'accesso a Google e l'utilizzo di un account YouTube con età
verificata.
+ DeArrow:
+ Show Original Details: Mostra dettagli originali
+ Show Modified Details: Mostra dettagli modificati
Videos:
#& Sort By
Sort By:
@@ -954,7 +960,7 @@ Share:
Mini Player: 'Mini visualizzatore'
Comments:
Comments: 'Commenti'
- Click to View Comments: 'Clicca per vedere i commenti'
+ Click to View Comments: 'Fai clic per vedere i commenti'
Getting comment replies, please wait: 'Sto scaricando le risposte ai commenti, per
favore attendi'
Show Comments: 'Mostra i commenti'
@@ -985,8 +991,8 @@ Comments:
Up Next: 'Prossimi video'
# Toast Messages
-Local API Error (Click to copy): 'Errore API Locale (Clicca per copiare)'
-Invidious API Error (Click to copy): 'Errore API Invidious (Clicca per copiare)'
+Local API Error (Click to copy): 'Errore API locale (fai clic per copiare)'
+Invidious API Error (Click to copy): 'Errore API Invidious (fai clic per copiare)'
Falling back to Invidious API: 'Torno alle API Invidious'
Falling back to Local API: 'Torno alle API locali'
Loop is now disabled: 'Il loop è ora disabilitato'
@@ -1002,9 +1008,9 @@ Canceled next video autoplay: 'Riproduzione automatica del prossimo video annull
Yes: 'Sì'
No: 'No'
A new blog is now available, {blogTitle}. Click to view more: 'Un nuovo blog è ora
- disponibile, {blogTitle}. Clicca per saperne di più'
+ disponibile, {blogTitle}. Fai clic per saperne di più'
Version {versionNumber} is now available! Click for more details: La versione {versionNumber}
- è ora disponibile! Clicca per maggiori dettagli
+ è ora disponibile! Fai clic per maggiori dettagli
Download From Site: Scarica dal sito
The playlist has been reversed: La playlist è stata invertita
Profile:
@@ -1070,9 +1076,9 @@ Tooltips:
Scroll Playback Rate Over Video Player: Mentre il cursore è sopra il video, tieni
premuto il tasto CTRL (Command su Mac) e scorri la rotella del mouse in avanti
o indietro per controllare la velocità di riproduzione. Tieni premuto il tasto
- CTRL (Command su Mac) e clicca con il tasto sinistro del mouse per tornare rapidamente
- alla velocità di riproduzione predefinita (1x a meno che non sia stata cambiata
- nelle Impostazioni).
+ CTRL (Command su Mac) e fai clic con il tasto sinistro del mouse per tornare
+ rapidamente alla velocità di riproduzione predefinita (1x a meno che non sia
+ stata cambiata nelle Impostazioni).
Skip by Scrolling Over Video Player: Usa la rotella di scorrimento per saltare
il video, in stile MPV.
Subscription Settings:
@@ -1097,6 +1103,9 @@ Tooltips:
External Link Handling: "Scegli il comportamento predefinito quando si fa clic
su un link che non può essere aperto in FreeTube.\nPer impostazione predefinita,
FreeTube aprirà il link cliccato nel browser predefinito.\n"
+ Open Deep Links In New Window: Gli URL passati a FreeTube, ad esempio tramite
+ estensioni del browser di reindirizzamento o argomenti della riga di comando,
+ vengono aperti in una nuova finestra.
External Player Settings:
Ignore Warnings: Non notifica gli avvisi quando il lettore esterno selezionato
non supporta l'azione richiesta (ad esempio invertire la playlist, etc.).
@@ -1131,10 +1140,10 @@ Tooltips:
UseDeArrowTitles: Sostituisci i titoli dei video coi titoli inviati dagli utenti
di DeArrow.
UseDeArrowThumbnails: Sostituisci le miniature dei video con le miniature di DeArrow.
-Playing Next Video Interval: Riproduzione del video successivo tra un attimo. Clicca
- per annullare. | Riproduzione del video successivo tra {nextVideoInterval} secondi.
- Clicca per annullare. | Riproduzione del video successivo tra {nextVideoInterval}
- secondi. Clicca per annullare.
+Playing Next Video Interval: Riproduzione del video successivo tra un attimo. Fai
+ clic per annullare. | Riproduzione del video successivo tra {nextVideoInterval}
+ secondi. Fai clic per annullare. | Riproduzione del video successivo tra {nextVideoInterval}
+ secondi. Fai clic per annullare.
More: Altro
Open New Window: Apri una nuova finestra
Default Invidious instance has been cleared: L'istanza predefinita di Invidious è
@@ -1224,3 +1233,7 @@ Keys:
arrowup: Freccia su
alt: Alt
KeyboardShortcutTemplate: '{label} ({shortcut})'
+Right-click or hold to see history: Fai clic con il tasto destro o tieni premuto per
+ visualizzare la cronologia
+Autoplay Interruption Timer: Riproduzione automatica annullata a causa di {autoplayInterruptionIntervalHours}
+ ore di inattività
diff --git a/static/locales/ja.yaml b/static/locales/ja.yaml
index 9b650937cc62b..2b5d02591e9a3 100644
--- a/static/locales/ja.yaml
+++ b/static/locales/ja.yaml
@@ -409,8 +409,6 @@ Settings:
Fetch Feeds from RSS: RSS から情報取得
Fetch Automatically: フィードの自動取得
Confirm Before Unsubscribing: 登録解除する前に確認画面を表示する
- Only Show Latest Video for Each Channel: 各チャンネルの最新動画のみを表示する
-
Privacy Settings:
Save Watched Progress: 再生位置の保存
Remember History: 履歴の保存
diff --git a/static/locales/nb-NO.yaml b/static/locales/nb-NO.yaml
index c4a604358d5b0..9c214f5180838 100644
--- a/static/locales/nb-NO.yaml
+++ b/static/locales/nb-NO.yaml
@@ -32,11 +32,21 @@ Forward: 'Framover'
# Anything shared among components / views should be put here
Global:
Videos: 'Videoer'
- Shorts: Kortvideoer
- Live: Direkte
- Community: Gemenskap
+ Shorts: Shorts-videoer
+ Live: Direktesendinger
+ Community: Fellesskap
# Search Bar
+ Counts:
+ Subscriber Count: 1 abonnent | {count} abonnenter
+ Watching Count: 1 seer | {count] seere
+ Channel Count: 1 kanal | {count} kanaler
+ Comment Count: 1 kommentar | {count} kommentarer
+ Video Count: 1 video | {count} videoer
+ View Count: 1 visning | {count} visninger
+ Like Count: 1 liker | {count} liker
+ Input Tags:
+ Length Requirement: Etiketten må minst være {number} tegn lang.
Search / Go to URL: 'Søk/gå til nettadresse'
# In Filter Button
Search Filters:
@@ -74,6 +84,18 @@ Search Filters:
Fetch more results: 'Hent flere resultater'
# Sidebar
There are no more results for this search: Søket ga ingen flere resultater
+ Features:
+ HD: HD
+ VR180: VR180
+ Subtitles: Underskrifter
+ Creative Commons: Creative Commons
+ 3D: 3D
+ Live: Direktesendt
+ 4K: 4K
+ Location: Sted
+ HDR: HDR
+ Features: Egenskaper
+ 360 Video: 360 Video
Subscriptions:
# On Subscriptions Page
Subscriptions: 'Abonnementer'
@@ -83,7 +105,7 @@ Subscriptions:
'Getting Subscriptions. Please wait.': 'Henter abonnementer. Vent.'
Refresh Subscriptions: Oppdater abonnementer
Getting Subscriptions. Please wait.: Henter abonnementer. Vennligst vent.
- Load More Videos: Last flere videoer
+ Load More Videos: Last inn flere videoer
This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: Denne
profilen har mange abonnementer. Påtvinger RSS for å unngå adgangsbegrensning
Error Channels: Kanaler med feil
@@ -93,6 +115,8 @@ Subscriptions:
Subscriptions Tabs: Abonnementsfaner
All Subscription Tabs Hidden: Alle abonnementsfaner er skjult. Opphev skjuling av
noen faner i «{subsection}»-delen av «{settingsSection}» for å vise innhold her.
+ Empty Posts: Kanalene du abonnerer på, har ikke noen innlegg for øyeblikket.
+ Load More Posts: Last inn flere poster
Trending:
Trending: 'På vei opp'
Trending Tabs: På vei opp-faner
@@ -106,6 +130,95 @@ User Playlists:
Your Playlists: 'Dine spillelister'
Empty Search Message: Ingen videoer i denne spillelisten samsvarer med søket ditt
Search bar placeholder: Søk i spilleliste
+ SinglePlaylistView:
+ Toast:
+ This playlist does not exist: Denne spillelisten finnes ikke
+ This video cannot be moved down.: Denne videoen kan ikke bli flyttet ned.
+ Video has been removed: Videoen har blitt fjernet
+ There were no videos to remove.: Det var ingen videoer å fjerne
+ There was an issue with updating this playlist.: Det oppstod et problem ved
+ oppdateringen av denne spillelisten.
+ "{videoCount} video(s) have been removed": 1 video har blitt fjernet | {videoCount}
+ videoer har blitt fjernet
+ Playlist has been updated.: Spilleliste har blitt endret
+ There was a problem with removing this video: Det oppstod et problem ved fjerningen
+ av denne videoen
+ This video cannot be moved up.: Denne videoen kan ikke bli flyttet opp.
+ Playlist {playlistName} has been deleted.: Spillelisten {playlistName} har blitt
+ fjernet.
+ This playlist is protected and cannot be removed.: Denne spillelisten er beskyttet,
+ og kan derfor ikke bli fjernet.
+ Some videos in the playlist are not loaded yet. Click here to copy anyway.: Noen
+ av videoene i spillelisten har ikke blitt lastet inn skikkelig, enda. Trykk
+ her for å kopiere, uansett.
+ Playlist name cannot be empty. Please input a name.: Spillelisten må ha et navn.
+ Vennligst gi den et navn.
+ Search for Videos: Søk etter videoer
+ AddVideoPrompt:
+ Allow Adding Duplicate Video(s): Tillat å legge til dupliserte videoer
+ Search in Playlists: Søk i spillelister
+ Save: Lagre
+ N playlists selected: '{playlistCount} valgt'
+ "{videoCount}/{totalVideoCount} Videos Will Be Added": '{videoCount}/{totalVideoCount}
+ videoer vil bli lagt til'
+ Toast:
+ You haven't selected any playlist yet.: Du har ikke valgt noen spillelister
+ enda.
+ "{videoCount} video(s) added to 1 playlist": 1 video lagt til 1 spilleliste
+ | {videoCount} videoer lagt til 1 spilleliste
+ Cancel: Avbryt
+ Add to Playlist: Legg til spilleliste
+ This playlist currently has no videos.: Denne spillelisten har ikke noen videoer
+ for øyeblikket.
+ Export Playlist: Eksporter denne spillelisten
+ Sort By:
+ EarliestCreatedFirst: Tidligst opprettet
+ Sort By: Sorter etter
+ EarliestUpdatedFirst: Tidligst endret
+ LatestPlayedFirst: Sist spilt av
+ EarliestPlayedFirst: Tidligst spilt av
+ LatestUpdatedFirst: Nylig endret
+ NameAscending: A-Å
+ NameDescending: Å-A
+ LatestCreatedFirst: Nylig opprettet
+ Add to Favorites: Legg til {playlistName}
+ Move Video Up: Flytt video opp
+ Move Video Down: Flytt video ned
+ Playlist Description: Beskrivelse på spilleliste
+ Save Changes: Lagre endringer
+ Copy Playlist: Kopier spilleliste
+ Playlist Name: Navn på spilleliste
+ Remove Watched Videos: Fjern sette videoer
+ Playlists with Matching Videos: Spillelister med like videoer
+ Create New Playlist: Opprett ny spilleliste
+ Remove from Favorites: Fjern fra {playlistName}
+ The playlist has been successfully exported: Spillelisten ble eksportert
+ Delete Playlist: Fjern spilleliste
+ CreatePlaylistPrompt:
+ Create: Opprett
+ New Playlist Name: Nytt navn på spilleliste
+ Toast:
+ There was an issue with creating the playlist.: Det oppstod et problem ved opprettelsen
+ av spillelisten.
+ There is already a playlist with this name. Please pick a different name.: Det
+ finnes allerede en spilleliste med det navnet. Vennligst velg et annet navn.
+ Playlist {playlistName} has been successfully created.: Spillelisten {playlistName}
+ har blitt opprettet.
+ Edit Playlist Info: Endre informasjon til spilleliste
+ Remove Duplicate Videos: Fjern duplikatvideoer
+ Remove from Playlist: Fjern fra spilleliste
+ You have no playlists. Click on the create new playlist button to create a new one.: Du
+ har ingen spillelister. Trykk på plusstegnet for å opprette en ny en.
+ Are you sure you want to delete this playlist? This cannot be undone: Er du sikker
+ på at du vil fjerne denne spillelisten? Dette kan ikke bli omgjort.
+ Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Er
+ du sikker på at du vil fjerne en duplikatvideo fra denne spillelisten? Dette kan
+ ikke bli omgjort. Er du sikker på at du vil fjerne {playlistItemCount} duplikate
+ videoer fra denne spillelisten? Denne kan ikke bli omgjort.
+ Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Er
+ du sikker på at du vil fjerne 1 sett video fra denne spillelisten? Dette kan ikke
+ bli omgjort. | Er du sikker på at du vil fjerne {playlistItemCount} sette videoer
+ fra denne spillelisten? Dette kan ikke bli omgjort.
History:
# On History Page
History: 'Historikk'
@@ -122,7 +235,7 @@ Settings:
bakende ved feil'
Enable Search Suggestions: 'Slå på søkeforslag'
Default Landing Page: 'Forvalgt landingsside'
- Locale Preference: 'Språkinnstilling'
+ Locale Preference: 'Innstillinger for språk'
Preferred API Backend:
Preferred API Backend: 'Foretrukket API-bakende'
Local API: 'Lokalt API'
@@ -132,11 +245,12 @@ Settings:
Grid: 'Rutenett'
List: 'Liste'
Thumbnail Preference:
- Thumbnail Preference: 'Miniatyrbilde-innstilling'
+ Thumbnail Preference: 'Innstillinger for miniatyrbilder'
Default: 'Forvalg'
Beginning: 'Begynnelsen'
Middle: 'Midten'
End: 'Slutten'
+ Hidden: Skjult
Region for Trending: 'Region for "På vei opp"'
#! List countries
Check for Updates: Se etter oppdateringer
@@ -155,8 +269,11 @@ Settings:
Ask Before Opening Link: Spør før åpning av lenke
Open Link: Åpne lenke
External Link Handling: Håndtering av eksterne lenker
+ Auto Load Next Page:
+ Label: Last inn den neste siden automatisk
+ Tooltip: Last inn flere sider og kommentarer automatisk.
Theme Settings:
- Theme Settings: 'Draktvalg'
+ Theme Settings: 'Tema'
Match Top Bar with Main Color: 'Tilpass topplinjen slik at den har samme farge
som hovedfargen'
Base Theme:
@@ -167,6 +284,8 @@ Settings:
Dracula: 'Dracula'
System Default: Systemforvalg
Catppuccin Mocha: Catppuccin-mokka
+ Pastel Pink: Pastellrosa
+ Nordic: Nordisk
Main Color Theme:
Main Color Theme: 'Hovedfarge'
Red: 'Rød'
@@ -212,9 +331,9 @@ Settings:
Disable Smooth Scrolling: Slå av myk rulling
Expand Side Bar by Default: Utvidet sidefelt som forvalg
Hide Side Bar Labels: Skjul sidefeltsetiketter
- Hide FreeTube Header Logo: Skjul FreeTube-tittellogo
+ Hide FreeTube Header Logo: Skjul FreeTubes tittel og logo
Player Settings:
- Player Settings: 'Videoavspillingsinnstillinger'
+ Player Settings: 'Innstillinger for avspilling av video'
Play Next Video: 'Spill av neste video'
Turn on Subtitles by Default: 'Undertekster som forvalg'
Autoplay Videos: 'Spill av videoer automatisk'
@@ -229,7 +348,7 @@ Settings:
Legacy Formats: 'Gamle formater'
Audio Formats: 'Lydformater'
Default Quality:
- Default Quality: 'Kvalitetsinnstilling'
+ Default Quality: 'Forvalt kvalitet'
Auto: 'Automatisk'
144p: '144p'
240p: '240p'
@@ -250,30 +369,31 @@ Settings:
Error:
Forbidden Characters: Forbudte tegn
Empty File Name: Tomt filnavn
- Enable: Skru på skjermavbildninger
+ Enable: Aktiver skjermbilde
Folder Label: Skjermavbildningsmappe
Folder Button: Velg mappe
- Format Label: Skjermavbildningsformat
- Quality Label: Skjermavbildningskvalitet
+ Format Label: Format for skjermbilde
+ Quality Label: Kvalitet for skjermbilde
Ask Path: Spør om hvor ting skal lagres
File Name Tooltip: Du kan bruke variablene nedenfor. %Y år, i 4 siffer. %M måned,
i 2 siffer. %D dag, i to siffer. %H time, i to siffer. %N minutt, i to siffer.
%s sekund, i to siffer. %T millisekunder, i tre siffer. %s videosekund. %t
videomillisekunder, i tre siffer. %i video-ID. Du kan også bruke «\», eller
«/» for å lage undermapper.
- Max Video Playback Rate: Maks. videoavspillingshastighet
+ Max Video Playback Rate: Maksimal hastighet for videoavspilling
Scroll Playback Rate Over Video Player: Avspillingshastighet ved rulling over
videoavspiller
Video Playback Rate Interval: Intervall for videoavspillingshastighet
Enter Fullscreen on Display Rotate: Fullskjermsvisning når skjermen roteres
Skip by Scrolling Over Video Player: Hopp over ved å rulle over videoavspiller
Privacy Settings:
- Privacy Settings: 'Personvernsinnstillinger'
+ Privacy Settings: 'Innstillinger for personvern'
Remember History: 'Husk historikk'
Save Watched Progress: 'Husk avspillingsposisjon'
- Clear Search Cache: 'Tøm søkehurtiglager'
- Are you sure you want to clear out your search cache?: 'Tøm søkehurtiglager?'
- Search cache has been cleared: 'Søkehurtiglager tømt'
+ Clear Search Cache: 'Tøm hurtiglager for søk'
+ Are you sure you want to clear out your search cache?: 'Er du sikker på at du
+ vil tømme hurtiglageret for søk?'
+ Search cache has been cleared: 'Hurtiglageret for søk har blitt tømt'
Remove Watch History: 'Fjern visningshistorikk'
Are you sure you want to remove your entire watch history?: 'Er du sikker på at
du vil fjerne hele visningshistorikken din?'
@@ -281,15 +401,23 @@ Settings:
Remove All Subscriptions / Profiles: Fjern alle abonnementer/profiler
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.
+ bli omgjort.
Save Watched Videos With Last Viewed Playlist: Lagre sette videoer med sist sette
spilleliste
+ Remove All Playlists: Fjern alle spillelister
+ Are you sure you want to remove all your playlists?: Er du sikker på at du vil
+ fjerne alle spillelistene dine?
+ All playlists have been removed: Alle spillelister har blitt fjernet
Subscription Settings:
- Subscription Settings: 'Abonnementsinnstillinger'
+ Subscription Settings: 'Innstillinger for abonnementer'
Hide Videos on Watch: 'Skjul sette videoer'
Fetch Feeds from RSS: Hent informasjonskanaler fra RSS
Fetch Automatically: Hent informasjonskanaler automatisk
+ Confirm Before Unsubscribing: Bekreft avslutning av abonnement
+ 'Limit the number of videos displayed for each channel': Begrens antallet videoer
+ vist for hver kanal
+ To: Til
Data Settings:
How do I import my subscriptions?: Hvordan importerer jeg abonnementene mine?
Unknown data key: Ukjent datanøkkel
@@ -321,7 +449,7 @@ Settings:
Import Subscriptions: Importer abonnementer
Select Export Type: Velg eksporttype
Select Import Type: Velg importtype
- Data Settings: Datainnstillinger
+ Data Settings: Innstillinger for data
All playlists has been successfully imported: Importerte alle spillelister
Subscription File: Abonnementsfil
History File: Historikkfil
@@ -346,44 +474,51 @@ Settings:
Proxy Host: Mellomtjenervert
Proxy Protocol: Mellomtjenerprotokoll
Enable Tor / Proxy: Skru på Tor/mellomtjener
- Proxy Settings: Mellomtjenerinnstillinger
+ Proxy Settings: Innstillinger for mellomtjenere
Distraction Free Settings:
Hide Trending Videos: Skjul "På vei opp"
Hide Video Likes And Dislikes: Skjul videogunst
- Distraction Free Settings: Distraksjonsfri-innstillinger
+ Distraction Free Settings: Innstillinger for andre tilpasninger
Hide Active Subscriptions: Skjul aktive abonnementer
Hide Recommended Videos: Skjul anbefalte videoer
Hide Comment Likes: Skjul kommentargunst
Hide Channel Subscribers: Skjul kanalabonnementer
Hide Popular Videos: Skjul "Mest populært"
Hide Video Views: Skjul videovisninger
- Hide Live Chat: Skjul sanntidssludring
+ Hide Live Chat: Skjul direktechat
Hide Playlists: Skjul spillelister
Hide Comments: Skjul kommentarer
- Hide Live Streams: "Skjul direktestrømmer"
+ Hide Live Streams: "Skjul direktesendinger"
Hide Chapters: Skjul kapitler
- Hide Channels Placeholder: Kanalnavn eller ID
+ Hide Channels Placeholder: Kanal-ID
Hide Channels: Skjul videoer fra kanaler
Hide Sharing Actions: Skjul delingshandlinger
Hide Upcoming Premieres: Skjul kommende premièrer
Hide Video Description: Skjul videobeskrivelse
Display Titles Without Excessive Capitalisation: Vis titler uten overdrevet bruk
av store bokstaver
- Hide Featured Channels: Skjult framhevede kanaler
- Hide Channel Community: Skjul kanalgemenskap
- Hide Channel Shorts: Skjul kanal-kortvideoer
+ Hide Featured Channels: Skjul fremhevede kanaler
+ Hide Channel Community: Skjul fane for "fellesskap" i kanaler
+ Hide Channel Shorts: Skjul fane for "Shorts-videoer" i kanaler
Sections:
Side Bar: Sidefelt
Channel Page: Kanalside
General: Generelt
Watch Page: Seerlogg
Subscriptions Page: Abonnementsside
- Hide Channel Playlists: Skjul kanalspilleliste
+ Hide Channel Playlists: Skjul fane for "spillelister" i kanalar
Hide Channel Releases: Skjul kanalpubliseringer
- Hide Channel Podcasts: Skjul kanal-nettradioopptak
+ Hide Channel Podcasts: Skjul fane for "podcaster" i kanaler
Hide Subscriptions Videos: Skjul abonnementsvideoer
- Hide Subscriptions Shorts: Skjul abonnements-kortvideoer
+ Hide Subscriptions Shorts: Skjul Shorts
Hide Subscriptions Live: Skjul abonnement det sendes direkte fra
+ Hide Profile Pictures in Comments: Skjul profilbilder i kommentarfeltet
+ Hide Channel Home: Skjule fane for "start" i kanaler
+ Hide Videos and Playlists Containing Text: Skjul videoer og spillelister som inneholder
+ tekst
+ Hide Channels Already Exists: Kanal-ID-en finnes allerede
+ Hide Videos and Playlists Containing Text Placeholder: Ord, del av ord eller setning
+ Hide Channels Invalid: Kanal-ID-en var ugyldig
The app needs to restart for changes to take effect. Restart and apply change?: Start
programmet på ny for å ta i bruk endringene?
SponsorBlock Settings:
@@ -392,7 +527,7 @@ Settings:
'SponsorBlock API Url (Default is https://sponsor.ajay.app)': SponsorBlock-API-nettadresse
(forvalget er https://sponsor.ajay.app)
Enable SponsorBlock: Skru på SponsorBlock
- SponsorBlock Settings: SponsorBlock-innstillinger
+ SponsorBlock Settings: Innstillinger for SponsorBlock
Skip Options:
Do Nothing: Ikke gjør noe
Prompt To Skip: Spør om å hoppe over
@@ -401,10 +536,12 @@ Settings:
Show In Seek Bar: Vis i blafringsfelt
Category Color: Kategorifarge
UseDeArrowTitles: Bruk DeArrow-videonavn
+ UseDeArrowThumbnails: Bruk DeArrow for miniatyrbilder
External Player Settings:
Custom External Player Arguments: Egendefinerte argumenter for ekstern avspiller
Custom External Player Executable: Egendefinert kjørbar fil for ekstern avspiller
- Ignore Unsupported Action Warnings: Ignorer advarsler om ustøttede handlinger
+ Ignore Unsupported Action Warnings: Ignorer advarsler om handlinger som ikke er
+ støttet
External Player Settings: Innstillinger for ekstern avspiller
External Player: Ekstern avspiller
Players:
@@ -412,7 +549,7 @@ Settings:
Name: Ingen
Download Settings:
Choose Path: Velg sti
- Download Settings: Nedlastingsinnstillinger
+ Download Settings: Innstillinger for nedlastninger
Download in app: Last ned i programmet
Open in web browser: Åpne i nettleser
Download Behavior: Nedlastingsadferd
@@ -420,7 +557,7 @@ Settings:
Parental Control Settings:
Parental Control Settings: Foreldrekontroll
Hide Search Bar: Skjul søkefelt
- Show Family Friendly Only: Kun vis familievennlige
+ Show Family Friendly Only: Vis kun familievennlig innhold
Hide Unsubscribe Button: Skjul knapp for opphevelse av abonnement
Experimental Settings:
Experimental Settings: Eksperimentelle innstillinger
@@ -429,7 +566,7 @@ Settings:
anbefales. Bruk på egen risiko.
Password Settings:
Remove Password: Fjern passord
- Password Settings: Passordinnstillinger
+ Password Settings: Innstillinger for passord
Set Password To Prevent Access: Sett et passord for å forhindre tilgang til innstillingene
Set Password: Sett passord
Password Dialog:
@@ -437,6 +574,7 @@ Settings:
Enter Password To Unlock: Skriv inn passord for å låse opp innstillinger
Password Incorrect: Feil passord
Password: Passord
+ Return to Settings Menu: Gå tilbake til menyen for innstillinger
About:
#On About page
About: 'Om'
@@ -449,7 +587,7 @@ About:
Website: Nettsted
Report a problem: Rapporter et problem
Source code: Kildekode
- Please read the: Les
+ Please read the: Vennligst les
Mastodon: Mastodon
Email: E-post
Blog: Blogg
@@ -458,13 +596,15 @@ About:
these people and projects: disse folkene og prosjektene
FreeTube is made possible by: FreeTube er gjort mulig av
Credits: Bidragsytere
- room rules: romregler
+ room rules: reglene for rommet
GitHub issues: GitHub-problemsporer
FreeTube Wiki: FreeTube-wiki
GitHub releases: GitHub-utgivelser
Beta: Beta
Chat on Matrix: Snakk med oss på Matrix
Discussions: Diskusjoner
+ Licensed under the: Lisensiert under
+ AGPLv3: AGPLv3
Channel:
Subscribe: 'Abonner'
Unsubscribe: 'Opphev abonnement'
@@ -509,11 +649,11 @@ Channel:
Community:
This channel currently does not have any posts: Denne kanalen har ingen oppføringer
Shorts:
- This channel does not currently have any shorts: Denne kanalen har ingen kortvideoer
+ This channel does not currently have any shorts: Denne kanalen har ingen Shorts-videoer
Live:
Live: Direkte
This channel does not currently have any live streams: Denne kanalen har ikke
- noen direktestrømmer
+ noen direktesendinger
Podcasts:
Podcasts: Nettradioopptak
This channel does not currently have any podcasts: Denne kanalen har ingen nettradioopptak
@@ -537,15 +677,15 @@ Video:
# As in a Live Video
Live: 'Direkte'
Live Now: 'Direkte'
- Live Chat: 'Sanntidssludring'
- Enable Live Chat: 'Slå på sanntidssludring'
- Live Chat is currently not supported in this build.: 'Sanntidssludring støttes ikke
- i denne versjonen.'
+ Live Chat: 'Direktechat'
+ Enable Live Chat: 'Slå på direktechat'
+ Live Chat is currently not supported in this build.: 'Direktechat støttes ikke i
+ denne versjonen.'
'Chat is disabled or the Live Stream has ended.': 'Sludringen er slått av, eller
så er direktesendingen avsluttet.'
- Live chat is enabled. Chat messages will appear here once sent.: 'Sanntidssludring
- er påslått. Meldinger vil vises her når de er sendt.'
- 'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Sanntidssludring
+ Live chat is enabled. Chat messages will appear here once sent.: 'Direktechat er
+ påslått. Meldinger vil vises her når de er sendt.'
+ 'Live Chat is currently not supported with the Invidious API. A direct connection to YouTube is required.': 'Direktechat
støttes for tiden ikke med Invidious-API-et. Direkte tilkobling til YouTube kreves.'
Published:
In less than a minute: Om mindre enn ett minutt
@@ -601,7 +741,7 @@ Video:
Premieres on: Har première
Premieres: Première
Upcoming: Kommende
- 'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Sanntidssludring
+ 'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Direktechat
er ikke tilgjengelig for denne strømmen. Opplasteren kan ha skrudd det av.
Videos:
#& Sort By
@@ -700,8 +840,8 @@ Profile:
Removed {profile} from your profiles: Fjernet {profile} fra dine profiler
Your default profile has been set to {profile}: 'Din forvalgte profil har blitt
satt til {profile}'
- Profile has been updated: Profil oppdatert
- Profile has been created: Profil opprettet
+ Profile has been updated: Profilen har blitt oppdatert
+ Profile has been created: Profilen har blitt opprettet
Your profile name cannot be empty: Profilnavnet ditt kan ikke stå tomt
Profile could not be found: Fant ikke profilen
All subscriptions will also be deleted.: Alle abonnementer vil også bli slettet.
@@ -730,13 +870,16 @@ Profile:
De samme kanalene vil bli slettet i enhver profil de finnes i.
Select None: Velg ingen
Delete Selected: Slett valgte
- Add Selected To Profile: Legg til valgt i profil
+ Add Selected To Profile: Legg til de valgte kanalene til profilen
Subscription List: Abonnementsliste
Profile Preview: Profilforhåndsvisning
Custom Color: Egendefinert farge
Profile Filter: Profilfilter
Profile Settings: Profilinnstillinger
Toggle Profile List: Slå av/på profilliste
+ Profile Name: Profilnavn
+ Create Profile Name: Lag profilnavn
+ Edit Profile Name: Endre profilnavn
This video is unavailable because of missing formats. This can happen due to country unavailability.: Denne
videoen er utilgjengelig grunnet manglende formater. Dette kan skyldes tilgangbegrensninger
i ditt land.
@@ -848,3 +991,34 @@ Hashtag:
This hashtag does not currently have any videos: Denne emneknaggen har ingen videoer
enda
checkmark: ✓
+Cancel: Avbryt
+Yes, Restart: Ja, start på nytt
+Search Listing:
+ Label:
+ Subtitles: Undertekster
+ 4K: 4K
+ Closed Captions: Undertekster
+ 8K: 8K
+ VR180: VR180
+ 360 Video: 360°
+ New: Ny
+ 3D: 3D
+Feed:
+ Refresh Feed: Oppdater {subscriptionName}
+Yes, Delete: Ja, slett
+Keys:
+ alt: Alt
+ arrowup: Piltast opp
+ arrowleft: Venstre piltast
+ arrowright: Høyre piltast
+ ctrl: Ctrl
+ arrowdown: Piltast ned
+Right-click or hold to see history: Høyreklikk eller hold musepekeren over for å se
+ historikk
+Close Banner: Lukk banner
+KeyboardShortcutTemplate: '{label} ({shortcut})'
+shortcutJoinOperator: +
+Yes, Open Link: Ja, åpne lenke
+Display Label: '{label}: {value}'
+Go to page: Gå til {page}
+Search character limit: Spørringen er over tegngrensen på {searchCharacterLimit}
diff --git a/static/locales/nl.yaml b/static/locales/nl.yaml
index 2709953292899..df79871d74811 100644
--- a/static/locales/nl.yaml
+++ b/static/locales/nl.yaml
@@ -448,8 +448,6 @@ Settings:
Hide Videos on Watch: 'Bekeken video''s verbergen'
Fetch Feeds from RSS: Feeds ophalen via RSS
Fetch Automatically: Feed automatisch ophalen
- Only Show Latest Video for Each Channel: Alleen nieuwste video voor elk kanaal
- tonen
Confirm Before Unsubscribing: Onbedoeld deabonneren voorkomen
Data Settings:
@@ -1015,8 +1013,8 @@ Tooltips:
kan worden geopend in FreeTube is aangeklikt.\nStandaard zal FreeTube de aangeklikte
link openen in je standaardbrowser.\n"
External Player Settings:
- Custom External Player Arguments: Aangepaste opdrachtregelargumenten,
- die je wil doorgeven aan de externe videospeler.
+ Custom External Player Arguments: Aangepaste opdrachtregelargumenten, die je wil
+ doorgeven aan de externe videospeler.
Ignore Warnings: Onderdruk waarschuwingen wanneer de geselecteerde videospeler
een opgegeven actie niet ondersteund (bijv. afspeellijsten omkeren, etc.).
Custom External Player Executable: Standaard gaat FreeTube er vanuit dat de gekozen
diff --git a/static/locales/pl.yaml b/static/locales/pl.yaml
index 47ee69843b2a2..75f3650bf3a47 100644
--- a/static/locales/pl.yaml
+++ b/static/locales/pl.yaml
@@ -304,6 +304,8 @@ Settings:
Auto Load Next Page:
Tooltip: Wczytuj kolejne strony oraz komentarze automatycznie.
Label: Automatycznie wczytaj kolejną stronę
+ Open Deep Links In New Window: Odnośniki URL przekazane do FreeTube otwieraj w
+ nowym oknie
Theme Settings:
Theme Settings: 'Wygląd'
Match Top Bar with Main Color: 'Dopasuj górną belkę do głównego koloru'
@@ -414,7 +416,7 @@ Settings:
4k: '4k'
8k: '8k'
Playlist Next Video Interval: Przerwa przed kolejną pozycją playlisty
- Next Video Interval: Czas do następnego filmu
+ Next Video Interval: Czas do następnego autoodtwarzania
Scroll Volume Over Video Player: Kontroluj głośność kółkiem myszy na obszarze
odtwarzacza
Display Play Button In Video Player: Pokaż przycisk odtwarzania na odtwarzaczu
@@ -443,15 +445,17 @@ Settings:
orientacji ekranu
Skip by Scrolling Over Video Player: Przewijaj film kółkiem myszy na obszarze
odtwarzacza
+ Autoplay Interruption Timer: Czas do przerwania autoodtwarzania
Subscription Settings:
Subscription Settings: 'Subskrypcje'
Hide Videos on Watch: 'Ukrywaj filmy po obejrzeniu'
Fetch Feeds from RSS: Pobierz subskrypcje z RSS
Fetch Automatically: Automatycznie odświeżaj subskrypcje
- Only Show Latest Video for Each Channel: Pokaż tylko najnowszy film z każdego
- kanału
Confirm Before Unsubscribing: Uniknij przypadkowego usunięcia subskrypcji
+ To: do
+ 'Limit the number of videos displayed for each channel': Ogranicz liczbę filmów
+ wyświetlanych dla każdego z kanałów
Privacy Settings:
Watch history has been cleared: Historia oglądania została wyczyszczona
Are you sure you want to remove your entire watch history?: Jesteś pewny/a, że
@@ -546,18 +550,18 @@ Settings:
Hide Channels Placeholder: ID kanału
Display Titles Without Excessive Capitalisation: Wyświetlaj tytuły nie nadużywając
wielkich liter i interpunkcji
- Hide Channel Community: Schowaj społeczność kanału
- Hide Channel Shorts: Schowaj filmy Short kanału
+ Hide Channel Community: Schowaj kartę kanału „Społeczność”
+ Hide Channel Shorts: Schowaj kartę kanału „Filmy Short”
Hide Featured Channels: Schowaj polecane kanały
- Hide Channel Playlists: Schowaj playlisty kanału
+ Hide Channel Playlists: Schowaj kartę kanału „Playlisty”
Sections:
Side Bar: Pasek boczny
Channel Page: Strona kanału
General: Ogólne
Watch Page: Strona odtwarzacza
Subscriptions Page: Strona subskrypcji
- Hide Channel Releases: Schowaj wydawnictwa kanału
- Hide Channel Podcasts: Schowaj podkasty kanału
+ Hide Channel Releases: Schowaj kartę kanału „Wydawnictwa”
+ Hide Channel Podcasts: Schowaj kartę kanału „Podkasty”
Hide Subscriptions Videos: Schowaj filmy z subskrypcji
Hide Subscriptions Shorts: Schowaj filmy Short z subskrypcji
Hide Subscriptions Live: Schowaj transmisje live z subskrypcji
@@ -574,6 +578,7 @@ Settings:
poniższy tekst
Hide Videos and Playlists Containing Text Placeholder: Słowo, fragment słowa,
lub wyrażenie
+ Hide Channel Home: Schowaj kartę kanału „Główna”
The app needs to restart for changes to take effect. Restart and apply change?: Aplikacja
musi zostać ponownie uruchomiona, aby zmiany zostały wprowadzone. Uruchomić ponownie
i zastosować zmiany?
@@ -738,7 +743,7 @@ Channel:
View Full Post: Zobacz całe posty
Viewing Posts Only Supported By Invidious: Wyświetlanie postów jest wspierane
tylko przez Invidious. Możesz zobaczyć zawartość nie korzystając z Invidious,
- przechodząc do zakładki „Społeczność” danego kanału.
+ przechodząc do karty „Społeczność” danego kanału.
Live:
Live: Transmisje
This channel does not currently have any live streams: Ten kanał nie ma obecnie
@@ -753,6 +758,9 @@ Channel:
Podcasts:
Podcasts: Podkasty
This channel does not currently have any podcasts: Ten kanał nie ma żadnych podkastów
+ Home:
+ Home: Główna
+ View Playlist: Zobacz playlistę
Video:
Mark As Watched: 'Oznacz jako obejrzany'
Remove From History: 'Usuń z historii'
@@ -878,6 +886,9 @@ Video:
MembersOnly: Filmy tylko dla wspierających nie mogą być odtwarzane przez FreeTube,
ponieważ wymagają danych logowania do konta Googla oraz płatną subskrypcje kanału.
Unlisted: Niepubliczny
+ DeArrow:
+ Show Original Details: Pokaż szczegóły oryginału
+ Show Modified Details: Pokaż zmodyfikowane szczegóły
Videos:
#& Sort By
Sort By:
@@ -1067,6 +1078,9 @@ Tooltips:
External Link Handling: "Wybierz domyślne zachowanie kiedy odnośnik, który nie
może zostać otworzony w FreeTube, został kliknięty.\nDomyślnie FreeTube otworzy
kliknięty odnośnik w domyślnej przeglądarce.\n"
+ Open Deep Links In New Window: Odnośniki URL przekazane do FreeTube (np. przez
+ rozszerzenie przeglądarki, albo argumenty linii komend) są otwierane w nowym
+ oknie.
Player Settings:
Default Video Format: Ustaw formaty, które zostaną użyte do odtwarzania filmów.
Formaty DASH obsługują wyższe rozdzielczości. Stare formaty są ograniczone do
@@ -1201,3 +1215,15 @@ Search Listing:
360 Video: 360°
'Blocked opening potentially unsafe URL': 'Zablokowano otwarcie potencjalnie niebezpiecznego
URL: "{url}".'
+Keys:
+ arrowup: Strzałka do góry
+ arrowright: Strzałka w prawo
+ arrowleft: Strzałka w lewo
+ arrowdown: Strzałka w dół
+ alt: Alt
+ ctrl: Ctrl
+Right-click or hold to see history: Kliknij prawym lub przytrzymaj, by zobaczyć historię
+shortcutJoinOperator: +
+KeyboardShortcutTemplate: '{label} ({shortcut})'
+Autoplay Interruption Timer: Automatyczne odtwarzanie zostało anulowane, z powodu
+ {autoplayInterruptionIntervalHours} godzin(y) braku aktywności
diff --git a/static/locales/pt-BR.yaml b/static/locales/pt-BR.yaml
index 06eacbd8f6f68..4082186482e5a 100644
--- a/static/locales/pt-BR.yaml
+++ b/static/locales/pt-BR.yaml
@@ -443,8 +443,6 @@ Settings:
Hide Videos on Watch: 'Ocultar vídeos após assisti-los'
Fetch Feeds from RSS: Buscar Informações através de RSS
Fetch Automatically: Buscar feed automaticamente
- Only Show Latest Video for Each Channel: Mostrar apenas vídeo mais recente para
- cada canal
Confirm Before Unsubscribing: Evitar cancelamento acidental de inscrições
Privacy Settings:
@@ -1082,8 +1080,7 @@ Tooltips:
clicado em seu navegador padrão.\n"
External Player Settings:
Custom External Player Arguments: Quaisquer argumentos de linha de comando personalizados,
- você deseja que seja passado para o player
- externo.
+ você deseja que seja passado para o player externo.
Ignore Warnings: Suprime os avisos para quando o player externo atual não suporta
a ação atual (por exemplo, reverter playlist, etc.).
Custom External Player Executable: Por padrão, o FreeTube assumirá que o player
diff --git a/static/locales/pt-PT.yaml b/static/locales/pt-PT.yaml
index 3a96b8c649265..269ae1acdfded 100644
--- a/static/locales/pt-PT.yaml
+++ b/static/locales/pt-PT.yaml
@@ -436,8 +436,6 @@ Settings:
Hide Videos on Watch: Ocultar vídeos visualizados
Fetch Feeds from RSS: Obter subscrições através de RSS
Fetch Automatically: Obter fontes automaticamente
- Only Show Latest Video for Each Channel: Mostrar apenas o último vídeo de cada
- canal
Confirm Before Unsubscribing: Impedir cancelamento acidental de subscrições
Distraction Free Settings:
Distraction Free Settings: Definições de distrações
@@ -973,8 +971,8 @@ Tooltips:
Fetch Automatically: Se ativa, FreeTube irá obter automaticamente as subscrições
ao abrir uma nova janela e/ou quando mudar de perfil.
External Player Settings:
- Custom External Player Arguments: Quaisquer argumentos de linha de comando,
- que quiser passar ao reprodutor externo.
+ Custom External Player Arguments: Quaisquer argumentos de linha de comando, que
+ quiser passar ao reprodutor externo.
Ignore Warnings: Ignorar avisos quando o reprodutor externo escolhido não suporte
uma ação (por exemplo, inverter listas de reprodução).
Custom External Player Executable: Por omissão, FreeTube assume que o reprodutor
diff --git a/static/locales/pt.yaml b/static/locales/pt.yaml
index a5f7fcd962056..0e6e0a02d53ac 100644
--- a/static/locales/pt.yaml
+++ b/static/locales/pt.yaml
@@ -461,8 +461,6 @@ Settings:
Hide Videos on Watch: 'Ocultar vídeos visualizados'
Fetch Feeds from RSS: 'Obter subscrições através de RSS'
Fetch Automatically: Obter fontes automaticamente
- Only Show Latest Video for Each Channel: Mostrar apenas o último vídeo de cada
- canal
Confirm Before Unsubscribing: Impedir cancelamento acidental de subscrições
Data Settings:
Data Settings: 'Dados'
@@ -1055,8 +1053,8 @@ Tooltips:
Fetch Automatically: Se ativa, FreeTube irá obter automaticamente as subscrições
ao abrir uma nova janela e/ou quando mudar de perfil.
External Player Settings:
- Custom External Player Arguments: Quaisquer argumentos de linha de comando,
- que quiser passar ao reprodutor externo.
+ Custom External Player Arguments: Quaisquer argumentos de linha de comando, que
+ quiser passar ao reprodutor externo.
Ignore Warnings: Ignorar avisos quando o reprodutor externo escolhido não suporte
uma ação (por exemplo, inverter listas de reprodução).
Custom External Player Executable: Por omissão, FreeTube assume que o reprodutor
diff --git a/static/locales/ro.yaml b/static/locales/ro.yaml
index 7de62eb940d78..cd8613e1aa0e1 100644
--- a/static/locales/ro.yaml
+++ b/static/locales/ro.yaml
@@ -438,8 +438,6 @@ Settings:
Fetch Feeds from RSS: 'Preluare de fluxuri din RSS'
Fetch Automatically: Preluați feedul automat
Confirm Before Unsubscribing: Confirmă înainte de dezabonare
- Only Show Latest Video for Each Channel: Arată doar cele mai noi videoclipuri
- pentru fiecare canal
Data Settings:
Data Settings: 'Setări de date'
Select Import Type: 'Selectează tipul de import'
diff --git a/static/locales/ru.yaml b/static/locales/ru.yaml
index ffbb1f3e54b86..1386d8e9c0630 100644
--- a/static/locales/ru.yaml
+++ b/static/locales/ru.yaml
@@ -297,6 +297,8 @@ Settings:
Auto Load Next Page:
Label: Авто-загрузка следующей страницы
Tooltip: Автоматическая загрузка дополнительных страниц и комментариев.
+ Open Deep Links In New Window: Открыть URL-адреса, переданные в FreeTube, в новом
+ окне
Theme Settings:
Theme Settings: 'Внешний вид'
Match Top Bar with Main Color: 'Использовать основной цвет к верхней панели'
@@ -439,8 +441,6 @@ Settings:
Hide Videos on Watch: 'Скрывать видео после просмотра'
Fetch Feeds from RSS: Получать ленты из RSS
Fetch Automatically: Автоматически получать ленту
- Only Show Latest Video for Each Channel: Показывать только последние видео для
- каждого канала
Confirm Before Unsubscribing: Подтвердить, прежде чем отписаться
Privacy Settings:
@@ -870,6 +870,9 @@ Video:
AgeRestricted: Видео с возрастными ограничениями нельзя смотреть через FreeTube,
так как для этого требуется вход в Google и использование подтвержденной учетной
записи YouTube.
+ DeArrow:
+ Show Original Details: Показать стандартные свойства
+ Show Modified Details: Показать модифицированные свойства
Videos:
#& Sort By
Sort By:
@@ -1200,3 +1203,4 @@ Keys:
arrowleft: Стрелка влево
arrowright: Стрелка вправо
arrowup: Стрелка вверх
+Right-click or hold to see history: ПКМ или зажми для просмотра истории
diff --git a/static/locales/sr.yaml b/static/locales/sr.yaml
index b17f179d6da64..4a12169896417 100644
--- a/static/locales/sr.yaml
+++ b/static/locales/sr.yaml
@@ -314,6 +314,8 @@ Settings:
Auto Load Next Page:
Label: Аутоматски учитај следећу страницу
Tooltip: Аутоматско учитавање додатних страница и коментара.
+ Open Deep Links In New Window: Отворите URL адресе прослеђене FreeTube-у у новом
+ прозору
Theme Settings:
Theme Settings: 'Тема'
Match Top Bar with Main Color: 'Усклади горњу траку са главном бојом'
@@ -449,9 +451,10 @@ Settings:
Video Playback Rate Interval: Интервал брзине репродукције видео снимка
Max Video Playback Rate: Максимална брзина репродукције видео снимка
Enter Fullscreen on Display Rotate: Уђи у цео екран при окретању екрана
- Next Video Interval: Интервал следећег видео снимка
+ Next Video Interval: Тајмер за одбројавање аутоплеја
Display Play Button In Video Player: Прикажи дугме за пуштање у плејеру видео
снимка
+ Autoplay Interruption Timer: Тајмер за прекид аутоплеја
Privacy Settings:
Privacy Settings: 'Приватност'
Remember History: 'Запамти историју'
@@ -478,9 +481,10 @@ Settings:
Hide Videos on Watch: 'Сакриј видео снимке на гледању'
Fetch Feeds from RSS: 'Прикупи фидове из RSS-а'
Fetch Automatically: Аутоматски прикупи фид
- Only Show Latest Video for Each Channel: Прикажи само најновији видео снимак за
- сваки канал
Confirm Before Unsubscribing: Избегни случајно отпраћивање
+ To: На
+ 'Limit the number of videos displayed for each channel': Ограничи број приказаних
+ видео снимака за сваки канал
Distraction Free Settings:
Distraction Free Settings: 'Без ометања'
Hide Video Views: 'Сакриј прегледе видео снимка'
@@ -502,14 +506,14 @@ Settings:
Channel Page: Страница канала
Subscriptions Page: Страница праћења
General: Опште
- Hide Channel Community: Сакриј заједницу канала
+ Hide Channel Community: Сакриј картицу „Заједница“ канала
Hide Subscriptions Videos: Сакриј видео снимке канала које пратите
Hide Comments: Сакриј коментаре
- Hide Channel Shorts: Сакриј Shorts снимке канала
+ Hide Channel Shorts: Сакриј картицу „Shorts“ канала
Hide Sharing Actions: Сакриј радње дељења
- Hide Channel Podcasts: Сакриј подкасте канала
+ Hide Channel Podcasts: Сакриј картицу „Подкасти“ канала
Hide Live Streams: Сакриј стримове уживо
- Hide Channel Playlists: Сакриј плејлисте канала
+ Hide Channel Playlists: Сакриј картицу „Плејлисте“ канала
Hide Subscriptions Community: Сакриј заједницу канала које пратите
Hide Channels: Сакриј видео снимке са канала
Hide Subscriptions Live: Сакриј стримове уживо канала које пратите
@@ -519,7 +523,7 @@ Settings:
Hide Featured Channels: Сакриј истакнуте канале
Hide Profile Pictures in Comments: Сакриј слике профила у коментарима
Hide Upcoming Premieres: Сакриј предстојеће премијере
- Hide Channel Releases: Сакриј издања канала
+ Hide Channel Releases: Сакриј картицу „Издања“ канала
Hide Channels Invalid: Наведени ID канала је неважећи
Hide Channels Disabled Message: Неки канали су блокирани помоћу ID-а и нису обрађени.
Функција је блокирана док се ти ID-ови ажурирају
@@ -529,6 +533,7 @@ Settings:
Hide Videos and Playlists Containing Text: Сакриј видео снимке и плејлисте које
садрже текст
Hide Videos and Playlists Containing Text Placeholder: Реч, део речи или фраза
+ Hide Channel Home: Сакриј картицу „Почетна“ канала
Data Settings:
Data Settings: 'Подаци'
Select Import Type: 'Избор врсте увоза'
@@ -800,6 +805,9 @@ Channel:
This channel is age-restricted and currently cannot be viewed in FreeTube.: Овај
канал је старосно ограничен и тренутно се не може гледати на FreeTube-у.
This channel does not exist: Овај канал не постоји
+ Home:
+ Home: Почетна
+ View Playlist: Погледај плејлисту
Video:
Mark As Watched: 'Означи као одгледано'
Remove From History: 'Уклони из историје'
@@ -923,6 +931,9 @@ Video:
AgeRestricted: Видео снимци са старосним ограничењемне могу се гледати на FreeTube-у
јер захтевају пријаву на Google налог и коришћење YouTube налога који је старосно
верификован.
+ DeArrow:
+ Show Modified Details: Прикажи измењене детаље
+ Show Original Details: Прикажи оригиналне детаље
Tooltips:
Subscription Settings:
Fetch Feeds from RSS: 'Када је омогућено, FreeTube ће користити RSS уместо свог
@@ -949,9 +960,12 @@ Tooltips:
снимке у тренду коју желите да се приказује.
Invidious Instance: Invidious инстанца на коју ће се FreeTube повезати за API
позиве.
+ Open Deep Links In New Window: URL адресе прослеђене FreeTube-у, као што су додаци
+ прегледача за преусмеравање или аргументи командне линије, отварају се у новом
+ прозору.
External Player Settings:
- Custom External Player Arguments: Сви прилагођени аргументи командне линије,
- желите да буду прослеђени спољном плејеру.
+ Custom External Player Arguments: Сви прилагођени аргументи командне линије, желите
+ да буду прослеђени спољном плејеру.
External Player: Избором спољног плејера ће приказати иконицу, за отварање видео
снимка (плејлисте, ако је подржана) у спољном плејеру, на сличици. Упозорење,
подешавања Invidious-а не утичу на спољне плејере.
@@ -1176,3 +1190,16 @@ Search Listing:
3D: 3D
'Blocked opening potentially unsafe URL': 'Блокирано отварање потенцијално небезбедне
URL адресе: „{url}“.'
+KeyboardShortcutTemplate: '{label} ({shortcut})'
+Keys:
+ alt: Alt
+ arrowdown: Стрелица доле
+ arrowleft: Стрелица лево
+ ctrl: Ctrl
+ arrowup: Стрелица горе
+ arrowright: Стрелица десно
+shortcutJoinOperator: +
+Right-click or hold to see history: Кликните десним тастером миша или задржите да
+ бисте видели историју
+Autoplay Interruption Timer: Аутоплеј је отказан због {autoplayInterruptionIntervalHours}
+ сати неактивности
diff --git a/static/locales/sv.yaml b/static/locales/sv.yaml
index b7d950b8adc69..9c43c9eed069d 100644
--- a/static/locales/sv.yaml
+++ b/static/locales/sv.yaml
@@ -397,8 +397,6 @@ Settings:
Hide Videos on Watch: 'Dölj video under visning'
Fetch Feeds from RSS: 'Hämta prenumerationer från RSS'
Fetch Automatically: Hämta flöde automatiskt
- Only Show Latest Video for Each Channel: Visa endast den senaste videon för varje
- kanal
Data Settings:
Data Settings: 'Datainställningar'
Select Import Type: 'Välj import-typen'
@@ -910,7 +908,8 @@ Tooltips:
kan öppnas i FreeTube är. \nStandard är att FreeTube kommer öppna länken i din
standardwebbläsare.\n"
External Player Settings:
- Custom External Player Arguments: Alla anpassade kommandoradsargument, ska skickas till den externa spelaren.
+ Custom External Player Arguments: Alla anpassade kommandoradsargument, ska skickas
+ till den externa spelaren.
Ignore Warnings: Dämpa varningar för när den aktuella externa spelaren inte stöder
den aktuella åtgärden (t.ex. backning av spellistor, etc.).
Custom External Player Executable: Som standard antar FreeTube att den valda externa
diff --git a/static/locales/tr.yaml b/static/locales/tr.yaml
index a3ddbc8c9cb32..7ae988605029f 100644
--- a/static/locales/tr.yaml
+++ b/static/locales/tr.yaml
@@ -455,8 +455,6 @@ Settings:
Hide Videos on Watch: 'İzlenmiş Videoları Gizle'
Fetch Feeds from RSS: 'Akışları RSS''den Getir'
Fetch Automatically: Akışı Otomatik Olarak Getir
- Only Show Latest Video for Each Channel: Her Kanal için Yalnızca En Son Videoyu
- Göster
Confirm Before Unsubscribing: Abonelikten Çıkmadan Önce Onayla
Data Settings:
Data Settings: 'Veri'
diff --git a/static/locales/uk.yaml b/static/locales/uk.yaml
index 7246060c7b1dd..bc2c86268c9b7 100644
--- a/static/locales/uk.yaml
+++ b/static/locales/uk.yaml
@@ -101,6 +101,7 @@ Search Filters:
HDR: HDR
VR180: VR180
3D: 3D
+ Creative Commons: Творчі Спільноти
Subscriptions:
# On Subscriptions Page
Subscriptions: 'Підписки'
@@ -109,9 +110,9 @@ Subscriptions:
профіль має велику кількість підписок. Використайте RSS щоб уникнути обмеження
швидкості'
'Your Subscription list is currently empty. Start adding subscriptions to see them here.': 'Ваш
- список підписок наразі порожній. Якщо ви хочете імпортувати свої підписки, ви
- можете перейти до Налаштувань Даних і вибрати Імпортувати Підписки або знайти
- канал і підписатися на нього.'
+ список підписок наразі порожній. Якщо ви хочете імпортувати свої підписки, перейдіть
+ до налаштувань даних і виберіть "Імпортувати підписки", або ви можете знайти канал
+ і підписатися на нього.'
'Getting Subscriptions. Please wait.': 'Отримання Підписок. Будь ласка, зачекайте.'
Refresh Subscriptions: 'Оновити Підписки'
Load More Videos: 'Завантажити більше відео'
@@ -132,10 +133,10 @@ Trending:
Music: Музика
Default: Типово
Most Popular: 'Найпопулярніші'
-Playlists: 'Списки відтворення'
+Playlists: 'Добірки'
User Playlists:
- Your Playlists: 'Ваші списки відтворення'
- Search bar placeholder: Шукати у добірці
+ Your Playlists: 'Ваші добірки'
+ Search bar placeholder: Шукати добірки
Empty Search Message: Немає відео в цій добірці, які відповідають вашому запиту
Create New Playlist: Створити новий список відтворення
Add to Playlist: Додати список відтворення
@@ -156,13 +157,109 @@ User Playlists:
Playlist Name: Назва списку відтворення
Edit Playlist Info: Змінити інформацію списку відтворення
Remove Watched Videos: Вилучити з переглянутих відео
+ Delete Playlist: Видалити добірку
+ Sort By:
+ Sort By: Сортувати за
+ LatestPlayedFirst: Нещодавно переглянуті
+ EarliestPlayedFirst: Найдавніше переглянуті
+ NameAscending: А-Я
+ LatestCreatedFirst: Нещодавно створено
+ EarliestCreatedFirst: Створено найраніше
+ NameDescending: Я-А
+ EarliestUpdatedFirst: Найстаріші оновлення
+ LatestUpdatedFirst: Останні оновлення
+ SinglePlaylistView:
+ Toast:
+ This playlist is now used for quick bookmark: Ця добірка тепер використовується
+ для швидких закладок
+ This playlist is now used for quick bookmark instead of {oldPlaylistName}. Click here to undo: Ця
+ добірка тепер використовується для швидких закладок замість {oldPlaylistName}.
+ Натисніть тут, щоб скасувати
+ This video cannot be moved up.: Це відео не можна перемістити вгору.
+ This video cannot be moved down.: Це відео не можна перемістити вниз.
+ Video has been removed: Відео було видалено
+ This playlist is already being used for quick bookmark.: Ця добірка вже використовується
+ для швидких закладок.
+ There was a problem with removing this video: Сталася помилка під час видалення
+ цього відео
+ Reverted to use {oldPlaylistName} for quick bookmark: Повернуто до використання
+ {oldPlaylistName} для швидких закладок
+ This playlist is protected and cannot be removed.: Цю добірку захищено, тому
+ її не можна видалити.
+ "{videoCount} video(s) have been removed": 1 відео було видалено | {videoCount}
+ відео було видалено
+ Playlist {playlistName} has been deleted.: Добірку {playlistName} було видалено.
+ This playlist does not exist: Ця добірка не існує
+ This playlist has a video with a duration error: Ця добірка містить принаймні
+ одне відео, яке не має тривалості, тому воно буде відсортоване так, ніби його
+ тривалість дорівнює нулю.
+ Some videos in the playlist are not loaded yet. Click here to copy anyway.: Деякі
+ відео в добірці ще не завантажено. Натисніть тут, щоб все одно скопіювати.
+ Playlist name cannot be empty. Please input a name.: Назва добірки не може бути
+ порожньою. Будь ласка, введіть назву.
+ Playlist has been updated.: Добірка була оновлена.
+ There was an issue with updating this playlist.: Сталася помилка при оновленні
+ цієї добірки.
+ There were no videos to remove.: Відео для видалення не знайдено.
+ Playlist {playlistName} is the new quick bookmark playlist.: Добірка {playlistName}
+ тепер є новою швидкою закладкою.
+ Search for Videos: Пошук відео
+ The playlist has been successfully exported: Добірку успішно експортовано
+ Export Playlist: Експортувати цю добірку
+ Are you sure you want to remove {playlistItemCount} watched videos from this playlist? This cannot be undone: Ви
+ впевнені, що хочете видалити 1 переглянуте відео з цієї добірки? Цю дію не можна
+ скасувати. | Ви впевнені, що хочете видалити {playlistItemCount} переглянутих
+ відео з цієї добірки? Цю дію не можна скасувати.
+ Are you sure you want to remove {playlistItemCount} duplicate videos from this playlist? This cannot be undone: Ви
+ впевнені, що хочете видалити 1 дубльоване відео з цієї добірки? Цю дію не можна
+ скасувати. | Ви впевнені, що хочете видалити {playlistItemCount} дубльованих відео
+ з цієї добірки? Цю дію не можна скасувати.
+ Are you sure you want to delete this playlist? This cannot be undone: Ви впевнені,
+ що хочете видалити цю добірку? Це неможливо скасувати.
+ Enable Quick Bookmark With This Playlist: Увімкнути швидке додавання в закладки
+ для цієї добірки
+ Quick Bookmark Enabled: Швидке додавання в закладки увімкнено
+ Cannot delete the quick bookmark target playlist.: Неможливо видалити добірку швидких
+ закладок.
+ Playlists with Matching Videos: Добірки з відповідними відео
+ Remove Duplicate Videos: Видалити дублікати відео
+ AddVideoPrompt:
+ Save: Зберегти
+ Search in Playlists: Пошук в добірках
+ Allow Adding Duplicate Video(s): Дозволити додавати дублікатів відео
+ Added {count} Times: Вже додано | Додано {count} разів
+ "{videoCount}/{totalVideoCount} Videos Will Be Added": '{videoCount}/{totalVideoCount}
+ Відео буде додано'
+ "{videoCount}/{totalVideoCount} Videos Already Added": '{videoCount}/{totalVideoCount}
+ Відео вже додано'
+ Toast:
+ "{videoCount} video(s) added to 1 playlist": 1 відео додано до 1 добірки | {videoCount}
+ відео додано до 1 добірки
+ "{videoCount} video(s) added to {playlistCount} playlists": 1 відео додано до
+ {playlistCount} добірок | {videoCount} відео додано до {playlistCount} добірок
+ You haven't selected any playlist yet.: Ви ще не вибрали жодної добірки.
+ N playlists selected: '{playlistCount} вибрано'
+ Select a playlist to add your N videos to: Виберіть добірку, до якої ви хочете
+ додати своє відео | Виберіть добірку, до якої ви хочете додати свої {videoCount}
+ відео
+ CreatePlaylistPrompt:
+ Create: Створити
+ Toast:
+ Playlist {playlistName} has been successfully created.: Добірку {playlistName}
+ успішно створено.
+ There was an issue with creating the playlist.: Сталася помилка під час створення
+ добірки.
+ There is already a playlist with this name. Please pick a different name.: Вже
+ існує добірка з такою назвою. Будь ласка, виберіть іншу назву.
+ New Playlist Name: Нова назва добірки
History:
# On History Page
History: 'Історія'
Watch History: 'Історія переглядів'
Your history list is currently empty.: 'Ваша історія переглядів на разі порожня.'
Search bar placeholder: Шукати в історії
- Empty Search Message: Немає відео в історії, які відповідають вашому запиту
+ Empty Search Message: У вашій історії немає відео, що відповідають вашому пошуку
+ Case Sensitive Search: Пошук з урахуванням регістру
Settings:
# On Settings Page
Settings: 'Налаштування'
@@ -170,7 +267,7 @@ Settings:
зміни набули чинності, необхідно перезавантижити застосунок. Перезавантажити та
застосувати зміни?'
General Settings:
- General Settings: 'Загальні налаштування'
+ General Settings: 'Загальні'
Check for Updates: 'Перевірити наявність оновлень'
Check for Latest Blog Posts: 'Перевірити останні повідомлення в блозі'
Fallback to Non-Preferred Backend on Failure: 'Коли у вашого головного API виникає
@@ -213,8 +310,13 @@ Settings:
Ask Before Opening Link: Запитувати, перш ніж відкрити посилання
Open Link: Відкрити посилання
External Link Handling: Обробка зовнішніх посилань
+ Auto Load Next Page:
+ Label: Автозавантаження наступної сторінки
+ Tooltip: Автоматично завантажувати додаткові сторінки та коментарі.
+ Open Deep Links In New Window: Відкривати URL-адреси, передані в FreeTube, в новому
+ вікні
Theme Settings:
- Theme Settings: 'Налаштування теми'
+ Theme Settings: 'Теми'
Match Top Bar with Main Color: 'Верхня панель основного кольору'
Expand Side Bar by Default: 'Усталено розгортати бічну панель'
Disable Smooth Scrolling: 'Відключити плавну прокрутку'
@@ -229,6 +331,11 @@ Settings:
Catppuccin Mocha: Catppuccin Mocha
Hot Pink: Гарячий рожевий
Pastel Pink: Пастельний рожевий
+ Gruvbox Dark: Gruvbox Темний
+ Solarized Light: Solarized Світлий
+ Nordic: Нордичний
+ Gruvbox Light: Gruvbox Світлий
+ Solarized Dark: Solarized Темна
Main Color Theme:
Main Color Theme: 'Основна кольорова тема'
Red: 'Червона'
@@ -268,12 +375,30 @@ Settings:
Catppuccin Mocha Flamingo: Catppuccin Mocha Flamingo
Catppuccin Mocha Yellow: Catppuccin Mocha Yellow
Catppuccin Mocha Rosewater: Catppuccin Mocha Rosewater
+ Gruvbox Dark Purple: Gruvbox Темно Фіолетовий
+ Gruvbox Light Blue: Gruvbox Світло Голубий
+ Solarized Cyan: Solarized Голубий
+ Solarized Green: Solarized Зелений
+ Gruvbox Light Orange: Gruvbox Світло Оранжевий
+ Solarized Yellow: Solarized Жовтий
+ Gruvbox Dark Green: Gruvbox Темно Зелений
+ Gruvbox Dark Blue: Gruvbox Темно Синій
+ Gruvbox Dark Aqua: Gruvbox Темна Аква
+ Gruvbox Dark Orange: Gruvbox Темно Оранжевий
+ Gruvbox Light Red: Gruvbox Світло Червоний
+ Gruvbox Light Purple: Gruvbox Світло Фіолетовий
+ Solarized Magenta: Solarized Пурпурний
+ Solarized Violet: Solarized Фіолетовий
+ Solarized Orange: Solarized Оранжевий
+ Solarized Red: Solarized Червоний
+ Gruvbox Dark Yellow: Gruvbox Темно Жовтий
+ Solarized Blue: Solarized Голубий
Secondary Color Theme: 'Другорядна кольорова тема'
#* Main Color Theme
Hide Side Bar Labels: Сховати мітки бічної панелі
Hide FreeTube Header Logo: Сховати логотип FreeTube із заголовка
Player Settings:
- Player Settings: 'Налаштування програвача'
+ Player Settings: 'Плеєр'
Play Next Video: 'Грати наступне відео'
Turn on Subtitles by Default: 'Увімкнути субтитри за замовченням'
Autoplay Videos: 'Автоматичне відтворення відео'
@@ -300,7 +425,7 @@ Settings:
4k: '4k'
8k: '8k'
Playlist Next Video Interval: Інтервал відтворення наступного відео
- Next Video Interval: Інтервал до наступного відео
+ Next Video Interval: Таймер автозапуску
Scroll Volume Over Video Player: Прокручування гучності на відеопрогравачі
Display Play Button In Video Player: Показувати кнопку відтворення у відеопрогравачі
Fast-Forward / Rewind Interval: Інтервал перемотування вперед/назад
@@ -327,8 +452,9 @@ Settings:
Enter Fullscreen on Display Rotate: Переходити в повноекранний режим за обертання
екрана
Skip by Scrolling Over Video Player: Пропустити гортанням відеопрогравача
+ Autoplay Interruption Timer: Таймер переривання автозапуску
Privacy Settings:
- Privacy Settings: 'Налаштування приватності'
+ Privacy Settings: 'Конфіденційність'
Remember History: 'Збрігати історію'
Save Watched Progress: 'Зберігати прогрес перегляду'
Clear Search Cache: 'Очистити пошуковий кеш'
@@ -344,15 +470,18 @@ Settings:
хочете вилучити всі підписки та профілі? Цю дію не можна скасувати.'
Save Watched Videos With Last Viewed Playlist: Зберегти переглянуті відео у список
відтворення, який ви переглядали останнім часом
+ All playlists have been removed: Усі добірки були видалені
+ Remove All Playlists: Видалити всі добірки
+ Are you sure you want to remove all your playlists?: Ви впевнені, що хочете видалити
+ всі свої добірки?
Subscription Settings:
- Subscription Settings: 'Налаштування підписки'
+ Subscription Settings: 'Підписка'
Hide Videos on Watch: 'Ховати відео при перегляді'
Fetch Feeds from RSS: 'Отримати канали з RSS'
Fetch Automatically: Автоматично отримувати стрічку
- Only Show Latest Video for Each Channel: Показувати лише останні відео для кожного
- каналу
+ Confirm Before Unsubscribing: Підтвердити перед скасуванням підписки
Distraction Free Settings:
- Distraction Free Settings: 'Налаштування зосередження'
+ Distraction Free Settings: 'Без відволікань'
Hide Video Views: 'Сховати перегляди відео'
Hide Video Likes And Dislikes: 'Приховати вподобайки до відео'
Hide Channel Subscribers: 'Не показувати підписників каналу'
@@ -362,7 +491,7 @@ Settings:
Hide Popular Videos: 'Не показувати популярні відео'
Hide Live Chat: 'Не показувати живий чат'
Hide Active Subscriptions: Сховати активні підписки
- Hide Playlists: Сховати списки відтворення
+ Hide Playlists: Сховати добірки
Hide Video Description: Сховати опис відео
Hide Comments: Сховати коментарі
Hide Sharing Actions: Сховати дії поширення
@@ -371,12 +500,12 @@ Settings:
Hide Upcoming Premieres: Сховати майбутні прем'єри
Hide Channels: Сховати відео з каналів
Hide Channels Placeholder: ID каналу
- Display Titles Without Excessive Capitalisation: Показувати заголовки без надмірно
- великих літер
+ Display Titles Without Excessive Capitalisation: Відображати заголовки без зайвої
+ капіталізації та пунктуації
Hide Featured Channels: Сховати пропоновані канали
- Hide Channel Playlists: Сховати списки відтворення каналу
- Hide Channel Community: Сховати спільноту каналу
- Hide Channel Shorts: Сховати Shorts каналу
+ Hide Channel Playlists: Сховати добірки каналу
+ Hide Channel Community: Сховати вкладку "Спільнота" каналу
+ Hide Channel Shorts: Сховати вкладку "Shorts" каналу
Sections:
Side Bar: Бічна панель
Channel Page: Сторінка каналу
@@ -384,8 +513,8 @@ Settings:
General: Загальні
Subscriptions Page: Сторінка підписок
Hide Subscriptions Videos: Сховати відео з підписок
- Hide Channel Podcasts: Сховати канали подкастів
- Hide Channel Releases: Сховати канали випусків
+ Hide Channel Podcasts: Сховати вкладку "Подкасти" каналу
+ Hide Channel Releases: Сховати вкладку "Випуски" каналу
Hide Subscriptions Shorts: Сховати Shorts із підписок
Hide Subscriptions Live: Сховати трансляції з підписок
Hide Profile Pictures in Comments: Сховати зображення профілю в коментарях
@@ -396,8 +525,13 @@ Settings:
Hide Channels Already Exists: ID каналу вже існує
Hide Channels API Error: Помилка під час пошуку користувача з наданим ID. Перевірте
ще раз, чи правильний ID.
+ Hide Channel Home: Сховати вкладку "Головна" каналу
+ Hide Videos and Playlists Containing Text Placeholder: Слово, фрагмент слова або
+ фраза
+ Hide Videos and Playlists Containing Text: Сховати відео та добірки, що містять
+ текст
Data Settings:
- Data Settings: 'Налаштування даних'
+ Data Settings: 'Дані'
Select Import Type: 'Оберіть тип імпорту'
Select Export Type: 'Оберіть тип експорту'
Import Subscriptions: 'Імпортувати підписки'
@@ -429,13 +563,21 @@ Settings:
Manage Subscriptions: Керування підписками
Playlist insufficient data: Недостатньо даних для списку відтворення "{playlist}",
пропуск елемента
- All playlists has been successfully exported: Усі списки відтворення успішно експортовано
+ All playlists has been successfully exported: Усі добірки успішно експортовано
Import Playlists: Імпорт добірок
Export Playlists: Експорт добірок
- All playlists has been successfully imported: Усі списки відтворення успішно імпортовано
+ All playlists has been successfully imported: Усі добірки успішно імпортовано
Playlist File: Файл списку відтворення
Subscription File: Файл підписки
History File: Файл історії
+ Export Playlists For Older FreeTube Versions:
+ Label: Експортувати добірки для старих версій FreeTube
+ Tooltip: "Ця опція експортує відео з усіх добірок в одну добірку під назвою
+ \"Улюблені\".\nЯк експортувати та імпортувати відео з добірок для старої версії
+ FreeTube:\n1. Експортуйте свої добірки з увімкненою цією опцією.\n2. Видаліть
+ усі свої наявні добірки за допомогою опції \"Видалити всі добірки\" в налаштуваннях
+ конфіденційності.\n3. Запустіть стару версію FreeTube та імпортуйте експортовані
+ добірки."
Proxy Settings:
Error getting network information. Is your proxy configured properly?: Помилка
отримання відомостей про мережу. Чи правильно налаштовано ваш проксі?
@@ -451,13 +593,18 @@ Settings:
Proxy Host: Проксі-вузол
Proxy Protocol: Проксі-протокол
Enable Tor / Proxy: Увімкнути Tor / Проксі
- Proxy Settings: Налаштування проксі
+ Proxy Settings: Проксі
+ Proxy Warning: FreeTube не має вбудованого проксі, але може підключатися до зовнішнього
+ проксі, такого як Tor, що працює на вашому комп'ютері, або зовнішній проксі,
+ наприклад, SOCKS5 проксі, який надають деякі VPN-сервіси. Якщо ця опція увімкнена,
+ переконайтеся, що ваш проксі/Tor налаштовані правильно, інакше FreeTube не зможе
+ завантажувати дані.
SponsorBlock Settings:
Notify when sponsor segment is skipped: Сповіщати про пропуск спонсорованого відтинка
'SponsorBlock API Url (Default is https://sponsor.ajay.app)': URL-адреса API SponsorBlock
(типово https://sponsor.ajay.app)
Enable SponsorBlock: Увімкнути SponsorBlock
- SponsorBlock Settings: Налаштування SponsorBlock
+ SponsorBlock Settings: SponsorBlock
Skip Options:
Skip Option: Опція пропуску
Auto Skip: Автопропуск
@@ -466,31 +613,35 @@ Settings:
Do Nothing: Нічого не робити
Category Color: Колір категорії
UseDeArrowTitles: Використовувати назви для відео DeArrow
+ UseDeArrowThumbnails: Використовувати DeArrow для ескізів
+ 'DeArrow Thumbnail Generator API Url (Default is https://dearrow-thumb.ajay.app)': 'URL
+ API генератора ескізів DeArrow (за замовчуванням: https://dearrow-thumb.ajay.app)'
External Player Settings:
Custom External Player Arguments: Власні аргументи зовнішнього програвача
Custom External Player Executable: Власний виконуваний зовнішній програвач
Ignore Unsupported Action Warnings: Нехтувати попередженнями про непідтримувані
дії
External Player: Зовнішній програвач
- External Player Settings: Параметри зовнішнього програвача
+ External Player Settings: Зовнішній плеєр
Players:
None:
Name: Немає
+ Ignore Default Arguments: Ігнорувати стандартні аргументи
Download Settings:
- Download Settings: Налаштування завантаження
+ Download Settings: Завантаження
Choose Path: Вибрати шлях
Ask Download Path: Запитувати шлях завантаження
Download Behavior: Поведінка завантаження
Download in app: Завантажити в застосунку
Open in web browser: Відкрити у переглядачі
Parental Control Settings:
- Parental Control Settings: Налаштування батьківського контролю
+ Parental Control Settings: Батьківський контроль
Hide Unsubscribe Button: Сховати кнопку скасування підписки
Show Family Friendly Only: Показати лише для сімейного перегляду
Hide Search Bar: Сховати панель пошуку
Experimental Settings:
Replace HTTP Cache: Заміна кешу HTTP
- Experimental Settings: Експериментальні налаштування
+ Experimental Settings: Експериментальні
Warning: Ці налаштування експериментальні, їхнє ввімкнення може призводити до
збоїв. Радимо робити резервні копії. Використовуйте на свій страх і ризик!
Password Dialog:
@@ -499,13 +650,15 @@ Settings:
Password Incorrect: Пароль неправильний
Password: Пароль
Password Settings:
- Password Settings: Налаштування пароля
+ Password Settings: Пароль
Set Password: Установити пароль
Remove Password: Вилучити пароль
Set Password To Prevent Access: Встановіть пароль, щоб запобігти доступу до налаштувань
+ Return to Settings Menu: Повернутися до налаштувань
+ Sort Settings Sections (A-Z): Сортувати розділи налаштувань (А-Я)
About:
#On About page
- About: 'Про'
+ About: 'Про додаток'
#& About
Donate: Підтримати
these people and projects: цим людям та проєктам
@@ -531,6 +684,8 @@ About:
Source code: Джерельний код
Beta: Бета
Discussions: Обговорення
+ Licensed under the: Ліцензовано за умовами
+ AGPLv3: AGPLv3
Profile:
Profile Select: 'Вибір профілю'
All Channels: 'Усі канали'
@@ -571,7 +726,7 @@ Profile:
бажаєте видалити вибрані канали? Канал не буде видалено з будь-якого іншого профілю.'
#On Channel Page
Profile Filter: Фільтр профілю
- Profile Settings: Налаштування профілю
+ Profile Settings: Профіль
Toggle Profile List: Перемкнути список профілів
Profile Name: Назва профілю
Edit Profile Name: Змінити назву профілю
@@ -597,14 +752,14 @@ Channel:
Oldest: 'Найдавніші'
Most Popular: 'Найпопулярніші'
Playlists:
- Playlists: 'Списки відтворення'
+ Playlists: 'Добірки'
This channel does not currently have any playlists: 'Цей канал наразі не має добірок'
Sort Types:
Last Video Added: 'Останнє додане відео'
Newest: 'Найновіші'
Oldest: 'Найдавніші'
About:
- About: 'Про'
+ About: 'Про канал'
Channel Description: 'Опис каналу'
Featured Channels: 'Рекомендовані канали'
Tags:
@@ -623,6 +778,11 @@ Channel:
votes: 'Голосів: {votes}'
Reveal Answers: Розгорнути відповіді
Hide Answers: Сховати відповіді
+ Video hidden by FreeTube: Відео приховане FreeTube
+ View Full Post: Переглянути повний пост
+ Viewing Posts Only Supported By Invidious: Перегляд постів підтримується лише
+ через Invidious. Перейдіть до вкладки спільноти каналу, щоб переглядати контент
+ без Invidious.
Live:
This channel does not currently have any live streams: Наразі на цьому каналі
немає прямих трансляцій
@@ -637,6 +797,9 @@ Channel:
This channel does not currently have any releases: Наразі на цьому каналі немає
випусків
Releases: Випуски
+ Home:
+ Home: Головна
+ View Playlist: Переглянути добірку
Video:
Mark As Watched: 'Позначити переглянутим'
Remove From History: 'Прибрати з історії'
@@ -723,6 +886,48 @@ Video:
Pause on Current Video: Призупинити на поточному відео
Unhide Channel: Показати канал
Hide Channel: Сховати канал
+ Player:
+ TranslatedCaptionTemplate: '{language} (перекладено з "{originalLanguage}")'
+ Stats:
+ Bandwidth: 'Пропускна здатність: {bandwidth} кбіт/с'
+ CodecsVideoAudio: 'Кодеки: {videoCodec} ({videoItag}) / {audioCodec} ({audioItag})'
+ Bitrate: 'Бітрейт: {bitrate} кбіт/с'
+ Volume: 'Гучність: {volumePercentage}%'
+ Buffered: 'Буферизація: {bufferedPercentage}%'
+ Dropped Frames / Total Frames: 'Втрачені кадри: {droppedFrames} / Загальні кадри:
+ {totalFrames}'
+ Player Dimensions: 'Розміри плеєра: {width}x{height}'
+ CodecAudio: 'Кодек: {audioCodec} ({audioItag})'
+ Stats: Статистика
+ Video ID: 'ID відео: {videoId}'
+ Media Formats: 'Медійні формати: {formats}'
+ Resolution: 'Роздільна здатність: {width}x{height}@{frameRate}'
+ CodecsVideoAudioNoItags: 'Кодеки: {videoCodec} / {audioCodec}'
+ Show Stats: Показати статистику
+ Full Window: Повний екран
+ Take Screenshot: Зробити скріншот
+ You appear to be offline: Виглядає, що ви не в мережі.
+ Playback will resume automatically when your connection comes back: Відтворення
+ відновиться автоматично, коли ваше підключення відновиться.
+ Exit Theatre Mode: Вийти з режиму кінотеатру
+ Exit Full Window: Вийти з повного екрану
+ Audio Tracks: Аудіотреки
+ Theatre Mode: Режим кінотеатру
+ Hide Stats: Сховати статистику
+ Skipped segment: Пропущено сегмент {segmentCategory}
+ IP block: YouTube заблокував вашу IP-адресу для перегляду відео. Будь ласка, спробуйте
+ змінити VPN або проксі.
+ Unlisted: Не в списку
+ AgeRestricted: Відео з віковими обмеженнями не можна переглядати за допомогою FreeTube,
+ оскільки вони вимагають входу через Google та використання відео-аккаунту YouTube
+ з підтвердженням віку.
+ More Options: Більше опцій
+ DeArrow:
+ Show Original Details: Показати оригінальні деталі
+ Show Modified Details: Показати змінені деталі
+ MembersOnly: Відео, доступні лише для учасників, не можна переглядати за допомогою
+ FreeTube, оскільки вони вимагають входу через Google та платної підписки на канал
+ завантажувача.
Videos:
#& Sort By
Sort By:
@@ -739,6 +944,17 @@ Playlist:
#* Published
#& Views
Playlist: Список відтворення
+ Sort By:
+ VideoDurationDescending: Тривалість (спочатку найдовші)
+ Custom: Користувацький
+ VideoTitleDescending: Заголовок (Я-А)
+ VideoTitleAscending: Заголовок (А-Я)
+ DateAddedOldest: Спочатку найстаріші добавлені
+ AuthorAscending: Автор (А-Я)
+ AuthorDescending: Автор (Я-А)
+ VideoDurationAscending: Тривалість (спочатку найкоротші)
+ Sort By: Сортувати за
+ DateAddedNewest: Спочатку новіші добавлені
Change Format:
Change Media Formats: 'Зміна форматів відео'
Use Dash Formats: 'Використовувати формати DASH'
@@ -748,6 +964,8 @@ Change Format:
відео'
Audio formats are not available for this video: 'Аудіоформати недоступні для цього
відео'
+ Legacy formats are not available for this video: Застарілі формати недоступні для
+ цього відео
Share:
Share Video: 'Поділитися відео'
Share Playlist: 'Поділитися списком відтворення'
@@ -796,7 +1014,8 @@ Comments:
Hearted: З сердечком
View {replyCount} replies: Переглянути {replyCount} відповідей
Subscribed: Слідкують
-Up Next: 'Далі вгору'
+ There are no comments available for this post: Коментарі для цього поста відсутні
+Up Next: 'Далі'
#Tooltips
Tooltips:
@@ -816,6 +1035,9 @@ Tooltips:
External Link Handling: "Визначте типову поведінку, коли натиснено на посилання,
яке не можна відкрити у FreeTube.\nТипово FreeTube відкриває натиснуте посилання
у вашому типовому переглядачі.\n"
+ Open Deep Links In New Window: URL-адреси, передані в FreeTube, наприклад через
+ розширення для браузера або аргументи командного рядка, відкриваються в новому
+ вікні.
Player Settings:
Proxy Videos Through Invidious: 'Під’єднається до Invidious, щоб дивитися відео,
а не встановлювати пряме з’єднання з YouTube.'
@@ -832,17 +1054,17 @@ Tooltips:
Skip by Scrolling Over Video Player: Використовувати колесо прокрутки для прокручування
відео в стилі MPV.
Subscription Settings:
- Fetch Feeds from RSS: 'Якщо ввімкнено, FreeTube використовуватиме RSS замість
- стандартного способу захоплення каналу підписки. RSS швидше і запобігає блокуванню
- ІР, але не надає дані, як-от тривалість відео або стан трансляції'
+ Fetch Feeds from RSS: 'При увімкненні FreeTube буде використовувати RSS замість
+ стандартного методу для отримання підписок. RSS є швидшим і запобігає блокуванню
+ IP-адрес, але не надає певної інформації, такої як тривалість відео, статус
+ в прямому ефірі або пости в спільноті'
# Toast Messages
Fetch Automatically: Якщо увімкнено, FreeTube автоматично отримуватиме вашу стрічку
підписок під час відкриття нового вікна та за перемикання профілю.
External Player Settings:
- Custom External Player Arguments: Будь-які нетипові аргументи командного рядка
- розділяються (';') крапкою з комою, ви бажаєте, щоб вас було перенаправлено
- до зовнішнього програвача.
+ Custom External Player Arguments: Будь-які користувацькі аргументи командного
+ рядка, які ви хочете передати зовнішньому плеєру.
Ignore Warnings: Заборонити попередження, якщо поточний зовнішній програвач не
підтримує поточну дію (наприклад, зворотна почерговість відтворення добірок
тощо).
@@ -853,17 +1075,25 @@ Tooltips:
відео (список відтворення, якщо підтримується) у зовнішньому програвачі, на
мініатюрі. Увага, налаштування Invidious не застосовуються до сторонніх програвачів.
DefaultCustomArgumentsTemplate: "(Типово: '{defaultCustomArguments}')"
+ Ignore Default Arguments: Не надсилати жодних стандартних аргументів зовнішньому
+ плеєру, окрім URL-адреси відео (наприклад, швидкість відтворення, URL-адреса
+ добірки тощо). Користувацькі аргументи все одно будуть передаватися.
Experimental Settings:
Replace HTTP Cache: Вимикає дисковий HTTP-кеш Electron і вмикає власний кеш зображень
у пам'яті. Призведе до збільшення використання оперативної пам'яті.
Distraction Free Settings:
- Hide Channels: Введіть ID, щоб сховати всі відео, списки відтворення та сам канал
- від появи в пошуку, тренді, найпопулярніших і рекомендованих. Введений ID каналу
- повинен повністю збігатися і чутливий до регістру.
+ Hide Channels: Введіть ID, щоб сховати всі відео, добірки та сам канал від появи
+ в пошуку, тренді, найпопулярніших і рекомендованих. Введений ID каналу повинен
+ повністю збігатися і чутливий до регістру.
Hide Subscriptions Live: Цей параметр перевизначається загальнодоступним налаштуванням
"{appWideSetting}" у розділі "{subsection}" "{settingsSection}"
+ Hide Videos and Playlists Containing Text: Введіть слово, фрагмент слова або фразу
+ (незалежно від регістру), щоб приховати всі відео та добірки, у заголовках яких
+ вона міститься, по всьому FreeTube, за винятком Історії, Ваших Добірок і відео
+ в межах добірок.
SponsorBlock Settings:
UseDeArrowTitles: Замінити назви відео на надіслані користувачем назви з DeArrow.
+ UseDeArrowThumbnails: Замінити ескізи відео на ескізи з DeArrow.
Local API Error (Click to copy): 'Помилка локального API (натисніть, щоб скопіювати)'
Invidious API Error (Click to copy): 'Помилка Invidious API (натисніть, щоб скопіювати)'
Falling back to Invidious API: 'Повернення до API Invidious'
@@ -926,6 +1156,7 @@ Chapters:
поточний розділ: {chapterName}'
'Chapters list hidden, current chapter: {chapterName}': 'Список розділів схований,
поточний розділ: {chapterName}'
+ Key Moments: Ключові моменти
Preferences: Налаштування
Ok: Гаразд
Hashtag:
@@ -939,9 +1170,10 @@ Channel Hidden: '{channel} додано до фільтра каналу'
Go to page: Перейти до {page}
Channel Unhidden: '{channel} вилучено з фільтра каналу'
Close Banner: Закрити банер
-Search character limit: Пошуковий запит перевищив ліміт у {searchCharacterLimit} символів
+Search character limit: Запит перевищує ліміт у {searchCharacterLimit} символів
Feed:
Refresh Feed: Оновити {subscriptionName}
+ Feed Last Updated: 'Останнє оновлення фіда {feedName}: {date}'
Search Listing:
Label:
4K: 4K
@@ -949,5 +1181,33 @@ Search Listing:
8K: 8K
VR180: VR180
360 Video: 360°
- New: New
+ New: Новинка
3D: 3D
+ Closed Captions: Закриті субтитри
+Right-click or hold to see history: ПКМ або утримуйте для перегляду історії
+Display Label: '{label}: {value}'
+Tag already exists: Тег "{tagName}" вже існує
+'Blocked opening potentially unsafe URL': 'Блоковано відкриття потенційно небезпечної
+ URL-адреси: "{url}".'
+shortcutJoinOperator: +
+Keys:
+ arrowright: Стрілка вправо
+ alt: Alt
+ ctrl: Ctrl
+ arrowdown: Стрілка вниз
+ arrowleft: Стрілка вліво
+ arrowup: Стрілка вгору
+checkmark: ✓
+KeyboardShortcutTemplate: '{label} ({shortcut})'
+Age Restricted:
+ This channel is age restricted: Цей канал має вікові обмеження
+ This video is age restricted: Це відео має вікові обмеження
+Trimmed input must be at least N characters long: Обрізаний ввід повинен бути хоча
+ б 1 символ довжиною | Обрізаний ввід повинен бути хоча б {length} символів довжиною
+Moments Ago: щойно
+Yes, Restart: Так, перезавантажити
+Yes, Open Link: Так, відкрити посилання
+Yes, Delete: Так, видалити
+Cancel: Скасувати
+Autoplay Interruption Timer: Автозапуск скасовано через {autoplayInterruptionIntervalHours}
+ годин бездіяльності
diff --git a/static/locales/vi.yaml b/static/locales/vi.yaml
index 9181ff360ac47..5c30339ee7729 100644
--- a/static/locales/vi.yaml
+++ b/static/locales/vi.yaml
@@ -422,8 +422,6 @@ Settings:
Hide Videos on Watch: 'Ẩn video khi đã xem'
Fetch Feeds from RSS: Cập nhật bảng tin qua RSS
Fetch Automatically: Tự động làm mới bảng tin
- Only Show Latest Video for Each Channel: Chỉ hiện video mới nhất cho mỗi kênh
-
Confirm Before Unsubscribing: Nhắc xác nhận trước khi hủy đăng ký
Data Settings:
How do I import my subscriptions?: Làm sao để tôi nhập đăng ký?
@@ -1044,8 +1042,8 @@ Tooltips:
Skip by Scrolling Over Video Player: Sử dụng con lăn chuột để bỏ qua video, kiểu
MPV.
External Player Settings:
- Custom External Player Arguments: Bất kỳ tham số dòng lệnh tùy chỉnh nào,
- bạn muốn được chuyển đến trình phát bên ngoài.
+ Custom External Player Arguments: Bất kỳ tham số dòng lệnh tùy chỉnh nào, bạn
+ muốn được chuyển đến trình phát bên ngoài.
Custom External Player Executable: Theo mặc định, FreeTube sẽ giả định rằng trình
phát bên ngoài đã chọn có thể được tìm thấy thông qua biến môi trường PATH.
Nếu cần, bạn có thể đặt một đường dẫn tuỳ chọn ở đây.
diff --git a/static/locales/vls.yaml b/static/locales/vls.yaml
index 6b30a767b7b6f..157d1c32c1590 100644
--- a/static/locales/vls.yaml
+++ b/static/locales/vls.yaml
@@ -460,7 +460,6 @@ Settings:
Hide Videos on Watch: ''
Fetch Feeds from RSS: ''
Fetch Automatically: ''
- Only Show Latest Video for Each Channel: ''
Confirm Before Unsubscribing: ''
Distraction Free Settings:
Distraction Free Settings: ''
diff --git a/static/locales/zh-CN.yaml b/static/locales/zh-CN.yaml
index b5c8556d1ee9c..f00d217f4a194 100644
--- a/static/locales/zh-CN.yaml
+++ b/static/locales/zh-CN.yaml
@@ -269,6 +269,7 @@ Settings:
Auto Load Next Page:
Label: 自动加载下一页
Tooltip: 自动加载额外页面和评论。
+ Open Deep Links In New Window: 在新窗口打开传递到 FreeTube 的 URL
Theme Settings:
Theme Settings: '主题'
Match Top Bar with Main Color: '顶部菜单栏对应主颜色'
@@ -379,7 +380,7 @@ Settings:
4k: '4k'
8k: '8k'
Playlist Next Video Interval: 播放列表 下一个影片时间间隔
- Next Video Interval: 下个视频的间隔时间
+ Next Video Interval: 自动播放倒计时器
Display Play Button In Video Player: 在视频播放器上显示播放按钮
Scroll Volume Over Video Player: 在视频播放器上滑动音量
Fast-Forward / Rewind Interval: 快进/快退间隔
@@ -401,14 +402,16 @@ Settings:
Folder Label: 截屏文件夹
Enter Fullscreen on Display Rotate: 屏幕旋转时进入全屏
Skip by Scrolling Over Video Player: 从视频播放器一侧滚动到另一侧来跳过视频
+ Autoplay Interruption Timer: 自动播放中断计时器
Subscription Settings:
Subscription Settings: '订阅'
Hide Videos on Watch: '观看时隐藏视频'
Fetch Feeds from RSS: 从RSS摘取推送
Fetch Automatically: 自动抓取订阅源
- Only Show Latest Video for Each Channel: 只显示每个频道的最新视频
Confirm Before Unsubscribing: 避免意外取消订阅
+ 'Limit the number of videos displayed for each channel': 限制每个频道展示的视频数
+ To: 到
Privacy Settings:
Are you sure you want to remove your entire watch history?: 您确认想移除您的全部观看历史记录?
Are you sure you want to clear out your search cache?: 您确定想清除您的搜索缓存?
@@ -784,6 +787,9 @@ Video:
MembersOnly: 无法用 FreeTube 观看仅供会员的视频,因这些视频需要 Google 登录以及上传者频道的付费会员身份。
AgeRestricted: 无法用 FreeTube 观看受限年龄的视频,因这些视频需要 Google 登录并使用验证过年龄的 YouTube 账户。
Unlisted: 不公开列出的视频
+ DeArrow:
+ Show Modified Details: 显示修改过的详情
+ Show Original Details: 显示原始详情
Videos:
#& Sort By
Sort By:
@@ -950,6 +956,7 @@ Tooltips:
Preferred API Backend: 选择FreeTube 要用于取得数据的后端。本地API 是内置提取器。Invidious API需要Invidious服务器才能连接。
Region for Trending: 热门区域让您挑选您想要显示哪个国家的热门视频。
External Link Handling: "选择单击一个无法在 FreeTube 中打开的链接时触发的默认操作。\n默认情况下,FreeTube 将在您的默认浏览器中打开所点击链接。\n"
+ Open Deep Links In New Window: 在新窗口由浏览器的重定向扩展或命令行变量传递到 FreeTube 的 URL。
External Player Settings:
External Player: 选择一个外部播放器将在缩略图上显示一个图标,用于在外部播放器中打开视频(播放列表,如果支持)。警告,Invidious 设置不影响外部播放器。
Custom External Player Executable: 默认情况下,FreeTube 假设选择的外部播放器可以通过 PATH 环境变量找到。如果需要,可以在这里设置自定义路径。
@@ -1049,3 +1056,8 @@ Keys:
arrowup: 向上箭头 (↑)
KeyboardShortcutTemplate: '{label} ({shortcut})'
shortcutJoinOperator: +
+Right-click or hold to see history: 右键单击或静止不动查看历史记录
+Autoplay Interruption Timer: 由于 {autoplayInterruptionIntervalHours} 小时不活跃,自动播放被取消
+Description:
+ Expand Description: '...更多'
+ Collapse Description: 显示较少
diff --git a/static/locales/zh-TW.yaml b/static/locales/zh-TW.yaml
index f89d099ab3543..d554db8bd8182 100644
--- a/static/locales/zh-TW.yaml
+++ b/static/locales/zh-TW.yaml
@@ -267,6 +267,7 @@ Settings:
Auto Load Next Page:
Tooltip: 自動載入額外頁面與留言。
Label: 自動載入下一頁
+ Open Deep Links In New Window: 在新視窗中開啟傳遞給 FreeTube 的 URL
Theme Settings:
Theme Settings: '主題'
Match Top Bar with Main Color: '頂部功能表欄對應主色彩'
@@ -405,7 +406,6 @@ Settings:
Hide Videos on Watch: '觀看時隱藏影片'
Fetch Feeds from RSS: 從RSS擷取推送
Fetch Automatically: 自動擷取 Feed
- Only Show Latest Video for Each Channel: 只顯示每個頻道的最新影片
Confirm Before Unsubscribing: 避免意外取消訂閱
Privacy Settings:
@@ -484,17 +484,17 @@ Settings:
Hide Channels: 隱藏頻道中的影片
Display Titles Without Excessive Capitalisation: 顯示沒有過多大寫與標點符號的標題
Hide Featured Channels: 隱藏精選頻道
- Hide Channel Playlists: 隱藏頻道播放清單
- Hide Channel Community: 隱藏頻道社群
- Hide Channel Shorts: 隱藏頻道短片
+ Hide Channel Playlists: 隱藏頻道「播放清單」分頁
+ Hide Channel Community: 隱藏頻道「社群」分頁
+ Hide Channel Shorts: 隱藏頻道「短片」分頁
Sections:
Side Bar: 側邊欄
Watch Page: 觀看頁面
General: 一般
Channel Page: 頻道頁面
Subscriptions Page: 訂閱頁面
- Hide Channel Podcasts: 隱藏頻道 Podcast
- Hide Channel Releases: 隱藏頻道發布
+ Hide Channel Podcasts: 隱藏頻道「Podcast」分頁
+ Hide Channel Releases: 隱藏頻道「發布」分頁
Hide Subscriptions Shorts: 隱藏訂閱短片
Hide Subscriptions Videos: 隱藏訂閱影片
Hide Subscriptions Live: 隱藏訂閱直播
@@ -506,6 +506,7 @@ Settings:
Hide Channels API Error: 使用提供的 ID 擷取使用者時發生錯誤。請再次檢查 ID 是否正確。
Hide Videos and Playlists Containing Text: 隱藏包含文字的影片與播放清單
Hide Videos and Playlists Containing Text Placeholder: 單字、單字片段或片語
+ Hide Channel Home: 隱藏頻道「首頁」分頁
The app needs to restart for changes to take effect. Restart and apply change?: 必須重新啟動應用程式以生效。重新啟動並套用變更嗎?
Proxy Settings:
Error getting network information. Is your proxy configured properly?: 取得網路資訊時發生錯誤。您的代理伺服器設定正確嗎?
@@ -666,6 +667,9 @@ Channel:
Releases:
Releases: 發布
This channel does not currently have any releases: 此頻道目前沒有任何發布
+ Home:
+ Home: 首頁
+ View Playlist: 檢視播放清單
Video:
Open in YouTube: '在 YouTube 中開啟'
Copy YouTube Link: '複製 YouTube 連結'
@@ -777,6 +781,9 @@ Video:
MembersOnly: 會員專屬影片無法使用 FreeTube 觀看,因為這些影片需要 Google 登入並且必須訂閱上傳者的付費頻道。
AgeRestricted: 由於需要 Google 登入並使用經過年齡驗證的 YouTube 帳戶,FreeTube 無法觀看有限制年齡的影片。
Unlisted: 未公開
+ DeArrow:
+ Show Original Details: 顯示原始詳細資訊
+ Show Modified Details: 顯示修改後的詳細資訊
Videos:
#& Sort By
Sort By:
@@ -945,8 +952,9 @@ Tooltips:
API 需要 Invidious 伺服器才能連線。
Region for Trending: 熱門影片區域可以讓您選擇想要顯示哪個國家的熱門影片。
External Link Handling: "選擇點擊後無法在 FreeTube 中開啟連結時的預設行為。\n預設情況下 FreeTube 將會在您的預設瀏覽器中開啟點擊的連結。\n"
+ Open Deep Links In New Window: 傳遞給 FreeTube 的 URL,例如透過重定向瀏覽器擴充套件或命令列引數,會在新視窗中開啟。
External Player Settings:
- Custom External Player Arguments: 任何您想要傳遞給外部播放程式的自訂命令列參數,以半形冒號分隔 (';')。
+ Custom External Player Arguments: 要傳給外部播放器的任何自訂命令列引數。
Ignore Warnings: 當目前的外部播放程式不支援目前動作時(例如反向播放清單等等),消除警告。
Custom External Player Executable: 預設情況下,FreeTube 會假設選定的外部播放程式可以透過 PATH 環境變數找到。如果需要的話,請在此設定自訂路徑。
External Player: 選擇外部播放程式將會在縮圖上顯示圖示,用來在外部播放程式中開啟影片(若支援的話,播放清單也可以)。警告:Invidious
@@ -1034,3 +1042,13 @@ Search Listing:
New: 新
3D: 3D
'Blocked opening potentially unsafe URL': 已阻止開啟可能不安全的 URL:「{url}」。
+KeyboardShortcutTemplate: '{label} ({shortcut})'
+shortcutJoinOperator: +
+Keys:
+ alt: Alt
+ ctrl: Ctrl
+ arrowdown: 向下方向鍵
+ arrowleft: 向左方向鍵
+ arrowright: 向右方向鍵
+ arrowup: 向上方向鍵
+Right-click or hold to see history: 右鍵點選或按住不放可以檢視歷史紀錄
diff --git a/yarn.lock b/yarn.lock
index dba470f88403a..affb9d4c72e64 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1121,10 +1121,10 @@
"@intlify/message-compiler" "9.14.2"
"@intlify/shared" "9.14.2"
-"@intlify/eslint-plugin-vue-i18n@^3.1.0":
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/@intlify/eslint-plugin-vue-i18n/-/eslint-plugin-vue-i18n-3.1.0.tgz#8e465afd2526789278d86faa9bc7c07ec2aff028"
- integrity sha512-X9EhEu7KHFUsbTteVYQn0BCPCh0udrC/KEukn5LWkkiZGY5jGtdLrxwUNIZudKGoXJOOxDfdEBPBnstm4QWVaQ==
+"@intlify/eslint-plugin-vue-i18n@^3.2.0":
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/@intlify/eslint-plugin-vue-i18n/-/eslint-plugin-vue-i18n-3.2.0.tgz#5213e9eda3c4b1391630ee31b654f9ff705918fb"
+ integrity sha512-TOIrD4tJE48WMyVIB8bNeQJJPYo1Prpqnm9Xpn1UZmcqlELhm8hmP8QyJnkgesfbG7hyiX/kvo63W7ClEQmhpg==
dependencies:
"@eslint/eslintrc" "^3.0.0"
"@intlify/core-base" "^9.12.0"
@@ -1146,7 +1146,7 @@
vue-eslint-parser "^9.3.1"
yaml-eslint-parser "^1.2.2"
-"@intlify/message-compiler@9.14.2":
+"@intlify/message-compiler@9.14.2", "@intlify/message-compiler@^9.12.0":
version "9.14.2"
resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.14.2.tgz#7217842ea1875d80bbf0f708e9b3ef5ad7c57a03"
integrity sha512-YsKKuV4Qv4wrLNsvgWbTf0E40uRv+Qiw1BeLQ0LAxifQuhiMe+hfTIzOMdWj/ZpnTDj4RSZtkXjJM7JDiiB5LQ==
@@ -1154,19 +1154,6 @@
"@intlify/shared" "9.14.2"
source-map-js "^1.0.2"
-"@intlify/message-compiler@^9.12.0":
- version "9.13.1"
- resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.13.1.tgz#ff8129badf77db3fb648b8d3cceee87c8033ed0a"
- integrity sha512-SKsVa4ajYGBVm7sHMXd5qX70O2XXjm55zdZB3VeMFCvQyvLew/dLvq3MqnaIsTMF1VkkOb9Ttr6tHcMlyPDL9w==
- dependencies:
- "@intlify/shared" "9.13.1"
- source-map-js "^1.0.2"
-
-"@intlify/shared@9.13.1":
- version "9.13.1"
- resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.13.1.tgz#202741d11ece1a9c7480bfd3f27afcf9cb8f72e4"
- integrity sha512-u3b6BKGhE6j/JeRU6C/RL2FgyJfy6LakbtfeVF8fJXURpZZTzfh3e05J0bu0XPw447Q6/WUp3C4ajv4TMS4YsQ==
-
"@intlify/shared@9.14.2":
version "9.14.2"
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.14.2.tgz#f7dceea32db44c9253e3f965745a42a5cb3a1883"
@@ -1915,125 +1902,125 @@
optionalDependencies:
prettier "^1.18.2 || ^2.0.0"
-"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1":
- version "1.12.1"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb"
- integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==
+"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6"
+ integrity sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==
dependencies:
- "@webassemblyjs/helper-numbers" "1.11.6"
- "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/helper-numbers" "1.13.2"
+ "@webassemblyjs/helper-wasm-bytecode" "1.13.2"
-"@webassemblyjs/floating-point-hex-parser@1.11.6":
- version "1.11.6"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431"
- integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==
+"@webassemblyjs/floating-point-hex-parser@1.13.2":
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz#fcca1eeddb1cc4e7b6eed4fc7956d6813b21b9fb"
+ integrity sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==
-"@webassemblyjs/helper-api-error@1.11.6":
- version "1.11.6"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768"
- integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==
+"@webassemblyjs/helper-api-error@1.13.2":
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz#e0a16152248bc38daee76dd7e21f15c5ef3ab1e7"
+ integrity sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==
-"@webassemblyjs/helper-buffer@1.12.1":
- version "1.12.1"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6"
- integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==
+"@webassemblyjs/helper-buffer@1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz#822a9bc603166531f7d5df84e67b5bf99b72b96b"
+ integrity sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==
-"@webassemblyjs/helper-numbers@1.11.6":
- version "1.11.6"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5"
- integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==
+"@webassemblyjs/helper-numbers@1.13.2":
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz#dbd932548e7119f4b8a7877fd5a8d20e63490b2d"
+ integrity sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==
dependencies:
- "@webassemblyjs/floating-point-hex-parser" "1.11.6"
- "@webassemblyjs/helper-api-error" "1.11.6"
+ "@webassemblyjs/floating-point-hex-parser" "1.13.2"
+ "@webassemblyjs/helper-api-error" "1.13.2"
"@xtuc/long" "4.2.2"
-"@webassemblyjs/helper-wasm-bytecode@1.11.6":
- version "1.11.6"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9"
- integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==
+"@webassemblyjs/helper-wasm-bytecode@1.13.2":
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz#e556108758f448aae84c850e593ce18a0eb31e0b"
+ integrity sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==
-"@webassemblyjs/helper-wasm-section@1.12.1":
- version "1.12.1"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf"
- integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==
+"@webassemblyjs/helper-wasm-section@1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz#9629dda9c4430eab54b591053d6dc6f3ba050348"
+ integrity sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==
dependencies:
- "@webassemblyjs/ast" "1.12.1"
- "@webassemblyjs/helper-buffer" "1.12.1"
- "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
- "@webassemblyjs/wasm-gen" "1.12.1"
+ "@webassemblyjs/ast" "1.14.1"
+ "@webassemblyjs/helper-buffer" "1.14.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.13.2"
+ "@webassemblyjs/wasm-gen" "1.14.1"
-"@webassemblyjs/ieee754@1.11.6":
- version "1.11.6"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a"
- integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==
+"@webassemblyjs/ieee754@1.13.2":
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz#1c5eaace1d606ada2c7fd7045ea9356c59ee0dba"
+ integrity sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==
dependencies:
"@xtuc/ieee754" "^1.2.0"
-"@webassemblyjs/leb128@1.11.6":
- version "1.11.6"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7"
- integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==
+"@webassemblyjs/leb128@1.13.2":
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.13.2.tgz#57c5c3deb0105d02ce25fa3fd74f4ebc9fd0bbb0"
+ integrity sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==
dependencies:
"@xtuc/long" "4.2.2"
-"@webassemblyjs/utf8@1.11.6":
- version "1.11.6"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a"
- integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==
-
-"@webassemblyjs/wasm-edit@^1.12.1":
- version "1.12.1"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b"
- integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==
- dependencies:
- "@webassemblyjs/ast" "1.12.1"
- "@webassemblyjs/helper-buffer" "1.12.1"
- "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
- "@webassemblyjs/helper-wasm-section" "1.12.1"
- "@webassemblyjs/wasm-gen" "1.12.1"
- "@webassemblyjs/wasm-opt" "1.12.1"
- "@webassemblyjs/wasm-parser" "1.12.1"
- "@webassemblyjs/wast-printer" "1.12.1"
-
-"@webassemblyjs/wasm-gen@1.12.1":
- version "1.12.1"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547"
- integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==
- dependencies:
- "@webassemblyjs/ast" "1.12.1"
- "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
- "@webassemblyjs/ieee754" "1.11.6"
- "@webassemblyjs/leb128" "1.11.6"
- "@webassemblyjs/utf8" "1.11.6"
-
-"@webassemblyjs/wasm-opt@1.12.1":
- version "1.12.1"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5"
- integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==
- dependencies:
- "@webassemblyjs/ast" "1.12.1"
- "@webassemblyjs/helper-buffer" "1.12.1"
- "@webassemblyjs/wasm-gen" "1.12.1"
- "@webassemblyjs/wasm-parser" "1.12.1"
-
-"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1":
- version "1.12.1"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937"
- integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==
- dependencies:
- "@webassemblyjs/ast" "1.12.1"
- "@webassemblyjs/helper-api-error" "1.11.6"
- "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
- "@webassemblyjs/ieee754" "1.11.6"
- "@webassemblyjs/leb128" "1.11.6"
- "@webassemblyjs/utf8" "1.11.6"
-
-"@webassemblyjs/wast-printer@1.12.1":
- version "1.12.1"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac"
- integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==
- dependencies:
- "@webassemblyjs/ast" "1.12.1"
+"@webassemblyjs/utf8@1.13.2":
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.13.2.tgz#917a20e93f71ad5602966c2d685ae0c6c21f60f1"
+ integrity sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==
+
+"@webassemblyjs/wasm-edit@^1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz#ac6689f502219b59198ddec42dcd496b1004d597"
+ integrity sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==
+ dependencies:
+ "@webassemblyjs/ast" "1.14.1"
+ "@webassemblyjs/helper-buffer" "1.14.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.13.2"
+ "@webassemblyjs/helper-wasm-section" "1.14.1"
+ "@webassemblyjs/wasm-gen" "1.14.1"
+ "@webassemblyjs/wasm-opt" "1.14.1"
+ "@webassemblyjs/wasm-parser" "1.14.1"
+ "@webassemblyjs/wast-printer" "1.14.1"
+
+"@webassemblyjs/wasm-gen@1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz#991e7f0c090cb0bb62bbac882076e3d219da9570"
+ integrity sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==
+ dependencies:
+ "@webassemblyjs/ast" "1.14.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.13.2"
+ "@webassemblyjs/ieee754" "1.13.2"
+ "@webassemblyjs/leb128" "1.13.2"
+ "@webassemblyjs/utf8" "1.13.2"
+
+"@webassemblyjs/wasm-opt@1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz#e6f71ed7ccae46781c206017d3c14c50efa8106b"
+ integrity sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==
+ dependencies:
+ "@webassemblyjs/ast" "1.14.1"
+ "@webassemblyjs/helper-buffer" "1.14.1"
+ "@webassemblyjs/wasm-gen" "1.14.1"
+ "@webassemblyjs/wasm-parser" "1.14.1"
+
+"@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz#b3e13f1893605ca78b52c68e54cf6a865f90b9fb"
+ integrity sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==
+ dependencies:
+ "@webassemblyjs/ast" "1.14.1"
+ "@webassemblyjs/helper-api-error" "1.13.2"
+ "@webassemblyjs/helper-wasm-bytecode" "1.13.2"
+ "@webassemblyjs/ieee754" "1.13.2"
+ "@webassemblyjs/leb128" "1.13.2"
+ "@webassemblyjs/utf8" "1.13.2"
+
+"@webassemblyjs/wast-printer@1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz#3bb3e9638a8ae5fdaf9610e7a06b4d9f9aa6fe07"
+ integrity sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==
+ dependencies:
+ "@webassemblyjs/ast" "1.14.1"
"@xtuc/long" "4.2.2"
"@webpack-cli/configtest@^2.1.1":
@@ -5845,10 +5832,10 @@ jest-worker@^29.7.0:
merge-stream "^2.0.0"
supports-color "^8.0.0"
-jintr@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/jintr/-/jintr-3.0.2.tgz#633ecc8da930d25f5004697acb5af4ff36628f26"
- integrity sha512-5g2EBudeJFOopjAX4exAv5OCCW1DgUISfoioCsm1h9Q9HJ41LmnZ6J52PCsqBlQihsmp0VDuxreAVzM7yk5nFA==
+jintr@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/jintr/-/jintr-3.1.0.tgz#5d4ec7ba695dfae3cc3f487545939a4ed1ad69b8"
+ integrity sha512-azhCHApkRfBH8INpiUCwKBYaNCdB5G+x3NApsI2MxQXSlgFAx7rap3YwE3JAkN08GO8f3ilZsGB0Yvc+412ntQ==
dependencies:
acorn "^8.8.0"
@@ -6016,71 +6003,71 @@ 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.8.5:
- version "1.8.5"
- resolved "https://registry.yarnpkg.com/lefthook-darwin-arm64/-/lefthook-darwin-arm64-1.8.5.tgz#38fca1049db0ad053e55a6c374cfc294fc40a5a9"
- integrity sha512-BXUcE+2TTkYRGhMB+6HwAbxhK72L4kFKbukb74VfSk9HYBFb/7IQXyUgsB2dik3LSTcDcl9SgOayzeLU9EqmGw==
-
-lefthook-darwin-x64@1.8.5:
- version "1.8.5"
- resolved "https://registry.yarnpkg.com/lefthook-darwin-x64/-/lefthook-darwin-x64-1.8.5.tgz#51e2001e9b042c4cd2df0d1222c6b8b52155b29d"
- integrity sha512-xkjYwVlJBQiJALR9jJi6MpIF161z6Td3gyVJoGII95h9hETYZV2J7ox4PUGufE5EV8P0AXWveWo8cJWhWVbssw==
-
-lefthook-freebsd-arm64@1.8.5:
- version "1.8.5"
- resolved "https://registry.yarnpkg.com/lefthook-freebsd-arm64/-/lefthook-freebsd-arm64-1.8.5.tgz#4bad183bef18e2e59ebd2aa03b8a56a7bf0281d5"
- integrity sha512-kL8+HxjAtMco824pZkBJiA3+q4djldNNw06atzgAxyy8/Kj+2NjlIaez88NPQHE4hAVMqtURzmRtnaruaRtT1g==
-
-lefthook-freebsd-x64@1.8.5:
- version "1.8.5"
- resolved "https://registry.yarnpkg.com/lefthook-freebsd-x64/-/lefthook-freebsd-x64-1.8.5.tgz#044e3939d0c3cf72c2179ddbb797c4b2d8abdad5"
- integrity sha512-fQfSUbAQVhLalZFl6sFGJQVBJK9EsQpmXrv1Qunhi8QOY/f07a2onsWb+jI9sp31ITTe2Jtzu0h31ZCBqTWxQw==
-
-lefthook-linux-arm64@1.8.5:
- version "1.8.5"
- resolved "https://registry.yarnpkg.com/lefthook-linux-arm64/-/lefthook-linux-arm64-1.8.5.tgz#3da0499e6ae4bf4835207f5b36c69c77bdefdeef"
- integrity sha512-gnBonAc3Heq+Sd+MzSbtLmZkYzSDZ+tTpLAfq2Q62qnVEZpWXFd3qfS2up5a7oUEDNcos7OHDqebSbowpNilZA==
-
-lefthook-linux-x64@1.8.5:
- version "1.8.5"
- resolved "https://registry.yarnpkg.com/lefthook-linux-x64/-/lefthook-linux-x64-1.8.5.tgz#1c9c449ff972a5a684e29040a2502039e2534e6e"
- integrity sha512-lLsbnXy58Syw6VMJS554HbfrBKUZ0mBWvDbr0DGoDBvFyxtvv5kFMbF/ZlRpLKl7Ds9IqCCCW0NpsjsixX4Z+A==
-
-lefthook-openbsd-arm64@1.8.5:
- version "1.8.5"
- resolved "https://registry.yarnpkg.com/lefthook-openbsd-arm64/-/lefthook-openbsd-arm64-1.8.5.tgz#ab1ea2e674b421fdab125d48f6d3d76790291258"
- integrity sha512-g3XFw/0q0T0Zd1vpPCO5l+ryFIyf+v/FFVPVb6HKvpDI4BYLFVzsZeVGzRiWZt1oJ0DI9qrrvdG4uJJBs4tSDQ==
-
-lefthook-openbsd-x64@1.8.5:
- version "1.8.5"
- resolved "https://registry.yarnpkg.com/lefthook-openbsd-x64/-/lefthook-openbsd-x64-1.8.5.tgz#bb5a423d8d27a3c3cfeaa94b590ce82d123918bd"
- integrity sha512-GmfnPUMMxa/ckHS2L7zIobWusaUmDWZU0zQj016QXGYS4SN8l5ZRU/ht4Tg6bbQSO6HYhWcyfIXB1XjPJPpG7w==
-
-lefthook-windows-arm64@1.8.5:
- version "1.8.5"
- resolved "https://registry.yarnpkg.com/lefthook-windows-arm64/-/lefthook-windows-arm64-1.8.5.tgz#a2afed656ad57c79841df2cce9a199f1724245e1"
- integrity sha512-e+6QAYD7PCsfVtPtnOMSC8PUiwnLCE9xCZq+dIK65/W/Ow84lSzHBR67Wl5MI3RiiGF2g8kulG+U1YZobXbdxQ==
-
-lefthook-windows-x64@1.8.5:
- version "1.8.5"
- resolved "https://registry.yarnpkg.com/lefthook-windows-x64/-/lefthook-windows-x64-1.8.5.tgz#ac4065a426e6ba05220f793cba1ac68b889c535e"
- integrity sha512-NPZwHbSWuGmYe5EEjkQbvRaotPW9/maKK7kexqrHxjzL/mOaoHSEYlW6ByPz2RB+bvgoTCkNRXlPiDDoDSYv+w==
-
-lefthook@^1.8.5:
- version "1.8.5"
- resolved "https://registry.yarnpkg.com/lefthook/-/lefthook-1.8.5.tgz#8c29bee1f3029e28f0ddeb040e0515a6a93ff945"
- integrity sha512-agsAaXJWoM9vOSVmKVYGPYT5IEzz4Upz0yWRva4L0mT+eObcesIrcMCnLLM+iGfweqC5exfDMm7BHUjTwoiGPg==
+lefthook-darwin-arm64@1.9.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/lefthook-darwin-arm64/-/lefthook-darwin-arm64-1.9.0.tgz#cefe3c8a29056d2349a2cc6dcaddee9771d99dc3"
+ integrity sha512-pClng2uWTqZ/FBC+YK0O4MlvphtMcw3xnYZYP4mOfM56gkSrMdsoG59AkBWB5zwxQymPiNFyO3H+JJbjvwmueA==
+
+lefthook-darwin-x64@1.9.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/lefthook-darwin-x64/-/lefthook-darwin-x64-1.9.0.tgz#872046e63ea42c40943238504711c9f394b73c38"
+ integrity sha512-PHQHJZHNadWhFan3Vvy24hMYMecR433t0NHODyBgILaZXOmoeMGcQYNHTmOb+R0148BKA/33l00m1CY14ZPqtw==
+
+lefthook-freebsd-arm64@1.9.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/lefthook-freebsd-arm64/-/lefthook-freebsd-arm64-1.9.0.tgz#f139d3206b2e615b0affca8cede96660a5571cd6"
+ integrity sha512-yuPJJJ3aDpMihqg1dfS75XgnzUYh+OqSZPmQp49s9RXKAWUCsBiDcirmrseDRbj3WVsatNGQldbV+5F5rNrxqw==
+
+lefthook-freebsd-x64@1.9.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/lefthook-freebsd-x64/-/lefthook-freebsd-x64-1.9.0.tgz#dfb7d7e9d45f8ce70dc86c5dd39471c4e32dc066"
+ integrity sha512-7By8mNLsc+EFJJkmeuC8tmYO8+i9oLBqDSHqnlzSNMK8EF5DV9DTAyNIHIbn0OIcwcCe6xBfwLZimeSkKxMZKg==
+
+lefthook-linux-arm64@1.9.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/lefthook-linux-arm64/-/lefthook-linux-arm64-1.9.0.tgz#388cd5ea50092b21f0d2d84b219f773a25370e7a"
+ integrity sha512-MYZD6j+ufryhENqjZe6POD3rT/0LFLfRtK4ddKKEqPGEy5wKpmXjt3ydfqTg6XAFzm6pyQO1zgwPuF40s5r3wQ==
+
+lefthook-linux-x64@1.9.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/lefthook-linux-x64/-/lefthook-linux-x64-1.9.0.tgz#205eb5ca1d67a132ab9024531a8ec20a4b84b414"
+ integrity sha512-xKh5/Lhjn7oI9AmUhtcArS1Y6RjDcxn0KKXAKURhwwZNFI0HGlusIYAF9U86MDqSPbfvEv+nRpq2i6au6Xp6Aw==
+
+lefthook-openbsd-arm64@1.9.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/lefthook-openbsd-arm64/-/lefthook-openbsd-arm64-1.9.0.tgz#78a889beef6171d96eb02074f73f6bff4397a47f"
+ integrity sha512-+3YNG0BVWO3CxBfO5GIDU31EWLZgfPU4M/NDqPekIBf8EUSiToXk9D4MNBAYnjjAfAezV/sdDeLm2Jg4l468UQ==
+
+lefthook-openbsd-x64@1.9.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/lefthook-openbsd-x64/-/lefthook-openbsd-x64-1.9.0.tgz#e381ab454c614248df5b9295216b5f4a4d0a7680"
+ integrity sha512-7DGR8oAa5N4JJ1s0hpDJMQ7AUAT3bDNcTPCFw2keVlmg29qMdIL4RIEbVau/DZ8GvZhzoOE8ddtgUH07PeUjRw==
+
+lefthook-windows-arm64@1.9.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/lefthook-windows-arm64/-/lefthook-windows-arm64-1.9.0.tgz#d6e9e7d31868b3e91948c468312a077cdb4e435a"
+ integrity sha512-t7LtUL3eDuprxomtuw74KBLXC+Clk1e/L+ofLy4Jw9t0FNPkFDouQv31IQ0HfS5d1aymNKjK/qbm+IOs1XZC6Q==
+
+lefthook-windows-x64@1.9.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/lefthook-windows-x64/-/lefthook-windows-x64-1.9.0.tgz#0911de961b98ea62556fb539a6ece7025e765ef7"
+ integrity sha512-q3L6tXUxicqiVbquyUIVuGlZo3fJ2y4HhgjINYVCRR+kdn+yqu5pR7Vre/I+LnWtm6V6CUmoV2rxx1fl/1lP1w==
+
+lefthook@^1.9.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/lefthook/-/lefthook-1.9.0.tgz#fe11036bad8a91523b81fa8f5e60b7bca64c8443"
+ integrity sha512-JF2J4+IEsWpTL2NRWXqUzNu3Nf0pfxMd+Io3kXm6rTQ04jpwh06f37VB5lc5L76kgxpjiBiuFoRlPOAY2je3YA==
optionalDependencies:
- lefthook-darwin-arm64 "1.8.5"
- lefthook-darwin-x64 "1.8.5"
- lefthook-freebsd-arm64 "1.8.5"
- lefthook-freebsd-x64 "1.8.5"
- lefthook-linux-arm64 "1.8.5"
- lefthook-linux-x64 "1.8.5"
- lefthook-openbsd-arm64 "1.8.5"
- lefthook-openbsd-x64 "1.8.5"
- lefthook-windows-arm64 "1.8.5"
- lefthook-windows-x64 "1.8.5"
+ lefthook-darwin-arm64 "1.9.0"
+ lefthook-darwin-x64 "1.9.0"
+ lefthook-freebsd-arm64 "1.9.0"
+ lefthook-freebsd-x64 "1.9.0"
+ lefthook-linux-arm64 "1.9.0"
+ lefthook-linux-x64 "1.9.0"
+ lefthook-openbsd-arm64 "1.9.0"
+ lefthook-openbsd-x64 "1.9.0"
+ lefthook-windows-arm64 "1.9.0"
+ lefthook-windows-x64 "1.9.0"
levn@^0.4.1:
version "0.4.1"
@@ -7976,17 +7963,17 @@ sanitize-filename@^1.6.3:
dependencies:
truncate-utf8-bytes "^1.0.0"
-sass-loader@^16.0.3:
- version "16.0.3"
- resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-16.0.3.tgz#17b944fab6702dc7a52c5d2a88cbfa38c39cdc75"
- integrity sha512-gosNorT1RCkuCMyihv6FBRR7BMV06oKRAs+l4UMp1mlcVg9rWN6KMmUj3igjQwmYys4mDP3etEYJgiHRbgHCHA==
+sass-loader@^16.0.4:
+ version "16.0.4"
+ resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-16.0.4.tgz#5c2afb755fbc0a45a004369efa11579518a39a45"
+ integrity sha512-LavLbgbBGUt3wCiYzhuLLu65+fWXaXLmq7YxivLhEqmiupCFZ5sKUAipK3do6V80YSU0jvSxNhEdT13IXNr3rg==
dependencies:
neo-async "^2.6.2"
-sass@^1.81.0:
- version "1.81.0"
- resolved "https://registry.yarnpkg.com/sass/-/sass-1.81.0.tgz#a9010c0599867909dfdbad057e4a6fbdd5eec941"
- integrity sha512-Q4fOxRfhmv3sqCLoGfvrC9pRV8btc0UtqL9mN6Yrv6Qi9ScL55CVH1vlPP863ISLEEMNLLuu9P+enCeGHlnzhA==
+sass@^1.82.0:
+ version "1.82.0"
+ resolved "https://registry.yarnpkg.com/sass/-/sass-1.82.0.tgz#30da277af3d0fa6042e9ceabd0d984ed6d07df70"
+ integrity sha512-j4GMCTa8elGyN9A7x7bEglx0VgSpNUG4W4wNedQ33wSMdnkqQCT8HTwOaVSV4e6yQovcu/3Oc4coJP/l0xhL2Q==
dependencies:
chokidar "^4.0.0"
immutable "^5.0.2"
@@ -8182,10 +8169,10 @@ setprototypeof@1.2.0:
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
-shaka-player@^4.12.3:
- version "4.12.3"
- resolved "https://registry.yarnpkg.com/shaka-player/-/shaka-player-4.12.3.tgz#f807e75d4ea699ea4e2d476962c13fc56d76bca3"
- integrity sha512-7lmRM/5YOCXP5SLm2y49D/7t59mM8kSmkqjIrhqi0BQWjEnZCZVvhicz/akJvJAvgNG+WCF1zkLuiKo8YtNdGw==
+shaka-player@^4.12.4:
+ version "4.12.4"
+ resolved "https://registry.yarnpkg.com/shaka-player/-/shaka-player-4.12.4.tgz#a22810763f36c7c3313545d4329420b520e6bda2"
+ integrity sha512-r3008gwhjgVZwLCpY8mT/OxLZQcJoqUKptKw7drsB8hV4lf1NhbTXxoNcM83lTS90iNMw2SXvk7vCLxyV/Uscw==
dependencies:
eme-encryption-scheme-polyfill "^2.1.6"
@@ -9377,16 +9364,16 @@ webpack-sources@^3.2.3:
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
-webpack@^5.96.1:
- version "5.96.1"
- resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.96.1.tgz#3676d1626d8312b6b10d0c18cc049fba7ac01f0c"
- integrity sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==
+webpack@^5.97.1:
+ version "5.97.1"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.97.1.tgz#972a8320a438b56ff0f1d94ade9e82eac155fa58"
+ integrity sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==
dependencies:
"@types/eslint-scope" "^3.7.7"
"@types/estree" "^1.0.6"
- "@webassemblyjs/ast" "^1.12.1"
- "@webassemblyjs/wasm-edit" "^1.12.1"
- "@webassemblyjs/wasm-parser" "^1.12.1"
+ "@webassemblyjs/ast" "^1.14.1"
+ "@webassemblyjs/wasm-edit" "^1.14.1"
+ "@webassemblyjs/wasm-parser" "^1.14.1"
acorn "^8.14.0"
browserslist "^4.24.0"
chrome-trace-event "^1.0.2"
@@ -9656,12 +9643,12 @@ 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@^11.0.1:
- version "11.0.1"
- resolved "https://registry.yarnpkg.com/youtubei.js/-/youtubei.js-11.0.1.tgz#5729bbf2df8dff58c3555140d23ae83c458f0b34"
- integrity sha512-ZsbOd+5XF2Ofi3FrLMfYd+f9g9H8xswlouFhjhOqbwT68dMJtX6CRGsHNj5VTFCR/+L/865x1lnUlllB2dDDTA==
+youtubei.js@^12.0.0:
+ version "12.0.0"
+ resolved "https://registry.yarnpkg.com/youtubei.js/-/youtubei.js-12.0.0.tgz#a36159918bf3e255a052d42afc9ca9c0f8c82a8c"
+ integrity sha512-pGmVb1I9b2gseqmuMx+BCajzVUi04+r+8zxj4Fk/iQaGQGvBCbY87Tu9mdvEgIQYTkkb4Fza7GZGrH9AjYNbrw==
dependencies:
"@bufbuild/protobuf" "^2.0.0"
- jintr "^3.0.2"
+ jintr "^3.1.0"
tslib "^2.5.0"
undici "^5.19.1"