diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 000000000..77feb3181
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,44 @@
+#
+# SPDX-FileCopyrightText: 2025 NewPipe e.V.
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+root = true
+
+[*.{kt,kts}]
+ktlint_standard_annotation = disabled
+ktlint_standard_argument-list-wrapping = disabled
+ktlint_standard_backing-property-naming = disabled
+ktlint_standard_blank-line-before-declaration = disabled
+ktlint_standard_blank-line-between-when-conditions = disabled
+ktlint_standard_chain-method-continuation = disabled
+ktlint_standard_class-signature = disabled
+ktlint_standard_comment-wrapping = disabled
+ktlint_standard_enum-wrapping = disabled
+ktlint_standard_function-expression-body = disabled
+ktlint_standard_function-literal = disabled
+ktlint_standard_function-signature = disabled
+ktlint_standard_indent = disabled
+ktlint_standard_kdoc = disabled
+ktlint_standard_max-line-length = disabled
+ktlint_standard_mixed-condition-operators = disabled
+ktlint_standard_multiline-expression-wrapping = disabled
+ktlint_standard_multiline-if-else = disabled
+ktlint_standard_no-blank-line-in-list = disabled
+ktlint_standard_no-consecutive-comments = disabled
+ktlint_standard_no-empty-first-line-in-class-body = disabled
+ktlint_standard_no-empty-first-line-in-method-block = disabled
+ktlint_standard_no-line-break-after-else = disabled
+ktlint_standard_no-semi = disabled
+ktlint_standard_no-single-line-block-comment = disabled
+ktlint_standard_package-name = disabled
+ktlint_standard_parameter-list-wrapping = disabled
+ktlint_standard_property-naming = disabled
+ktlint_standard_spacing-between-declarations-with-annotations = disabled
+ktlint_standard_spacing-between-declarations-with-comments = disabled
+ktlint_standard_statement-wrapping = disabled
+ktlint_standard_string-template-indent = disabled
+ktlint_standard_trailing-comma-on-call-site = disabled
+ktlint_standard_trailing-comma-on-declaration-site = disabled
+ktlint_standard_try-catch-finally-spacing = disabled
+ktlint_standard_when-entry-bracing = disabled
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 686ae233a..069f003f4 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -3,6 +3,19 @@
NewPipe contribution guidelines
===============================
+## AI policy
+
+* Using generative AI to develop new features or making larger code changes is generally prohibited. Please refrain from contributions which are heavily depending on AI generated source code because they are usually lacking a fundamental understanding of the overall project structure and thus come with poor quality. However, you are allowed to use gen. AI if you
+ * are aware of the project structure,
+ * ensure that the generated code follows the project structure,
+ * fully understand the generated code, and
+ * review the generated code completely.
+* Using AI to find the root cause of bugs and generating small fixes might be acceptable. However, gen. AI often does not fix the underlying problem but is trying to fix the symptoms. If you are using AI to fix bugs, ensure that the root cause is tackled.
+* The use of AI to generate documentation is allowed. We ask you to thoroughly check the quality of generated documentation – wrong, misleading or uninformative documentation is useless and wastes the reader's time. Ensure that reasoning is documented.
+* Using generative AI to write or fill in PR or issue templates is prohibited. Those texts are often lengthy and miss critical information.
+* PRs and issues that do not follow this AI policy can be closed without further explanation.
+
+
## Crash reporting
Report crashes through the **automated crash report system** of NewPipe.
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 52897f1ac..60c94ad25 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -26,6 +26,8 @@ body:
required: true
- label: "I have read and understood the [contribution guidelines](https://github.com/TeamNewPipe/NewPipe/blob/dev/.github/CONTRIBUTING.md)."
required: true
+ - label: "I have read and understood the [AI policy](https://github.com/TeamNewPipe/NewPipe/blob/dev/.github/CONTRIBUTING.md#ai-policy). The content of this bug report is not generated by AI."
+ required: true
- type: input
id: app-version
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index 31ef92c44..97a3e38b5 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -25,6 +25,8 @@ body:
required: true
- label: "I have read and understood the [contribution guidelines](https://github.com/TeamNewPipe/NewPipe/blob/dev/.github/CONTRIBUTING.md)."
required: true
+ - label: "I have read and understood the [AI policy](https://github.com/TeamNewPipe/NewPipe/blob/dev/.github/CONTRIBUTING.md#ai-policy). The content of this request is not generated by AI."
+ required: true
- type: textarea
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 407c00a39..2af1556d4 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -2,7 +2,7 @@
#### What is it?
- [ ] Bugfix (user facing)
-- [ ] Feature (user facing)
+- [ ] Feature (user facing) ⚠️ **Your PR must target the [`refactor`](https://github.com/TeamNewPipe/NewPipe/tree/refactor) branch**
- [ ] Codebase improvement (dev facing)
- [ ] Meta improvement to the project (dev facing)
@@ -32,3 +32,5 @@ The APK can be found by going to the "Checks" tab below the title. On the left p
#### Due diligence
- [ ] I read the [contribution guidelines](https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md).
+- [ ] The proposed changes follow the [AI policy](https://github.com/TeamNewPipe/NewPipe/blob/HEAD/.github/CONTRIBUTING.md#ai-policy).
+- [ ] I tested the changes using an emulator or a physical device.
diff --git a/.github/workflows/build-release-apk.yml b/.github/workflows/build-release-apk.yml
index 0fad8e169..b558d90dd 100644
--- a/.github/workflows/build-release-apk.yml
+++ b/.github/workflows/build-release-apk.yml
@@ -7,11 +7,11 @@ jobs:
release:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
with:
ref: 'master'
- - uses: actions/setup-java@v4
+ - uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
@@ -32,7 +32,7 @@ jobs:
mv app/build/outputs/apk/release/*.apk "app/build/outputs/apk/release/NewPipe_v$VERSION_NAME.apk"
- name: "Upload APK"
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v6
with:
name: app
path: app/build/outputs/apk/release/*.apk
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f6708fa83..d42c5a0b4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -37,8 +37,8 @@ jobs:
contents: read
steps:
- - uses: actions/checkout@v4
- - uses: gradle/wrapper-validation-action@v2
+ - uses: actions/checkout@v6
+ - uses: gradle/actions/wrapper-validation@v4
- name: create and checkout branch
# push events already checked out the branch
@@ -48,7 +48,7 @@ jobs:
run: git checkout -B "$BRANCH"
- name: set up JDK
- uses: actions/setup-java@v4
+ uses: actions/setup-java@v5
with:
java-version: 21
distribution: "temurin"
@@ -58,7 +58,7 @@ jobs:
run: ./gradlew assembleDebug lintDebug testDebugUnitTest --stacktrace -DskipFormatKtlint
- name: Upload APK
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v6
with:
name: app
path: app/build/outputs/apk/debug/*.apk
@@ -72,15 +72,15 @@ jobs:
- api-level: 21
target: default
arch: x86
- - api-level: 33
- target: google_apis # emulator API 33 only exists with Google APIs
+ - api-level: 35
+ target: default
arch: x86_64
permissions:
contents: read
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- name: Enable KVM
run: |
@@ -89,7 +89,7 @@ jobs:
sudo udevadm trigger --name-match=kvm
- name: set up JDK
- uses: actions/setup-java@v4
+ uses: actions/setup-java@v5
with:
java-version: 21
distribution: "temurin"
@@ -104,7 +104,7 @@ jobs:
script: ./gradlew connectedCheck --stacktrace
- name: Upload test report when tests fail # because the printed out stacktrace (console) is too short, see also #7553
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v6
if: failure()
with:
name: android-test-report-api${{ matrix.api-level }}
@@ -118,19 +118,19 @@ jobs:
contents: read
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Set up JDK
- uses: actions/setup-java@v4
+ uses: actions/setup-java@v5
with:
java-version: 21
distribution: "temurin"
cache: 'gradle'
- name: Cache SonarCloud packages
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
diff --git a/.github/workflows/image-minimizer.yml b/.github/workflows/image-minimizer.yml
index d9241c33b..264a0ac6c 100644
--- a/.github/workflows/image-minimizer.yml
+++ b/.github/workflows/image-minimizer.yml
@@ -17,9 +17,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- - uses: actions/setup-node@v4
+ - uses: actions/setup-node@v6
with:
node-version: 16
@@ -27,7 +27,7 @@ jobs:
run: npm i probe-image-size@7.2.3 --ignore-scripts
- name: Minimize simple images
- uses: actions/github-script@v7
+ uses: actions/github-script@v8
timeout-minutes: 3
with:
script: |
diff --git a/.gitignore b/.gitignore
index 1352b6917..49267a9f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@ captures/
*.iml
*~
.weblate
+.kotlin
*.class
app/debug/
app/release/
diff --git a/app/build.gradle b/app/build.gradle
deleted file mode 100644
index d6c93c1f7..000000000
--- a/app/build.gradle
+++ /dev/null
@@ -1,360 +0,0 @@
-import com.android.tools.profgen.ArtProfileKt
-import com.android.tools.profgen.ArtProfileSerializer
-import com.android.tools.profgen.DexFile
-
-plugins {
- id "com.android.application"
- id "kotlin-android"
- id "kotlin-kapt"
- id "kotlin-parcelize"
- id "checkstyle"
- id "org.sonarqube" version "4.0.0.2929"
-}
-
-android {
- compileSdk 34
- namespace 'org.schabi.newpipe'
-
- defaultConfig {
- applicationId "org.schabi.newpipe"
- resValue "string", "app_name", "NewPipe"
- minSdk 21
- targetSdk 33
- if (System.properties.containsKey('versionCodeOverride')) {
- versionCode System.getProperty('versionCodeOverride') as Integer
- } else {
- versionCode 1005
- }
- versionName "0.28.0"
- if (System.properties.containsKey('versionNameSuffix')) {
- versionNameSuffix System.getProperty('versionNameSuffix')
- }
-
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
-
- javaCompileOptions {
- annotationProcessorOptions {
- arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
- }
- }
- }
-
- buildTypes {
- debug {
- debuggable true
-
- // suffix the app id and the app name with git branch name
- def workingBranch = getGitWorkingBranch()
- def normalizedWorkingBranch = workingBranch.replaceFirst("^[^A-Za-z]+", "").replaceAll("[^0-9A-Za-z]+", "")
- if (normalizedWorkingBranch.isEmpty() || workingBranch == "master" || workingBranch == "dev") {
- // default values when branch name could not be determined or is master or dev
- applicationIdSuffix ".debug"
- resValue "string", "app_name", "NewPipe Debug"
- } else {
- applicationIdSuffix ".debug." + normalizedWorkingBranch
- resValue "string", "app_name", "NewPipe " + workingBranch
- archivesBaseName = 'NewPipe_' + normalizedWorkingBranch
- }
- }
-
- release {
- if (System.properties.containsKey('packageSuffix')) {
- applicationIdSuffix System.getProperty('packageSuffix')
- resValue "string", "app_name", "NewPipe " + System.getProperty('packageSuffix')
- archivesBaseName = 'NewPipe_' + System.getProperty('packageSuffix')
- }
- minifyEnabled true
- shrinkResources false // disabled to fix F-Droid's reproducible build
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- archivesBaseName = 'app'
- }
- }
-
- lint {
- checkReleaseBuilds false
- // Or, if you prefer, you can continue to check for errors in release builds,
- // but continue the build even when errors are found:
- abortOnError false
- // suppress false warning ("Resource IDs will be non-final in Android Gradle Plugin version
- // 5.0, avoid using them in switch case statements"), which affects only library projects
- disable 'NonConstantResourceId'
- }
-
- compileOptions {
- // Flag to enable support for the new language APIs
- coreLibraryDesugaringEnabled true
-
- sourceCompatibility JavaVersion.VERSION_17
- targetCompatibility JavaVersion.VERSION_17
- encoding 'utf-8'
- }
-
- kotlinOptions {
- jvmTarget = JavaVersion.VERSION_17
- }
-
- sourceSets {
- androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
- }
-
- androidResources {
- generateLocaleConfig = true
- }
-
- buildFeatures {
- viewBinding true
- buildConfig true
- }
-
- packagingOptions {
- resources {
- // remove two files which belong to jsoup
- // no idea how they ended up in the META-INF dir...
- excludes += ['META-INF/README.md', 'META-INF/CHANGES',
- // 'COPYRIGHT' belongs to RxJava...
- 'META-INF/COPYRIGHT']
- }
- }
-}
-
-ext {
- checkstyleVersion = '10.12.1'
-
- androidxLifecycleVersion = '2.6.2'
- androidxRoomVersion = '2.6.1'
- androidxWorkVersion = '2.8.1'
-
- stateSaverVersion = '1.4.1'
- exoPlayerVersion = '2.18.7'
- googleAutoServiceVersion = '1.1.1'
- groupieVersion = '2.10.1'
- markwonVersion = '4.6.2'
-
- leakCanaryVersion = '2.12'
- stethoVersion = '1.6.0'
-}
-
-configurations {
- checkstyle
- ktlint
-}
-
-checkstyle {
- getConfigDirectory().set(rootProject.file("checkstyle"))
- ignoreFailures false
- showViolations true
- toolVersion = checkstyleVersion
-}
-
-tasks.register('runCheckstyle', Checkstyle) {
- source 'src'
- include '**/*.java'
- exclude '**/gen/**'
- exclude '**/R.java'
- exclude '**/BuildConfig.java'
- exclude 'main/java/us/shandian/giga/**'
-
- classpath = configurations.checkstyle
-
- showViolations true
-
- reports {
- xml.getRequired().set(true)
- html.getRequired().set(true)
- }
-}
-
-def outputDir = "${project.buildDir}/reports/ktlint/"
-def inputFiles = project.fileTree(dir: "src", include: "**/*.kt")
-
-tasks.register('runKtlint', JavaExec) {
- inputs.files(inputFiles)
- outputs.dir(outputDir)
- getMainClass().set("com.pinterest.ktlint.Main")
- classpath = configurations.ktlint
- args "src/**/*.kt"
- jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED")
-}
-
-tasks.register('formatKtlint', JavaExec) {
- inputs.files(inputFiles)
- outputs.dir(outputDir)
- getMainClass().set("com.pinterest.ktlint.Main")
- classpath = configurations.ktlint
- args "-F", "src/**/*.kt"
- jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED")
-}
-
-afterEvaluate {
- if (!System.properties.containsKey('skipFormatKtlint')) {
- preDebugBuild.dependsOn formatKtlint
- }
- preDebugBuild.dependsOn runCheckstyle, runKtlint
-}
-
-sonar {
- properties {
- property "sonar.projectKey", "TeamNewPipe_NewPipe"
- property "sonar.organization", "teamnewpipe"
- property "sonar.host.url", "https://sonarcloud.io"
- }
-}
-
-dependencies {
-/** Desugaring **/
- coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.0.4'
-
-/** NewPipe libraries **/
- // You can use a local version by uncommenting a few lines in settings.gradle
- // Or you can use a commit you pushed to GitHub by just replacing TeamNewPipe with your GitHub
- // name and the commit hash with the commit hash of the (pushed) commit you want to test
- // This works thanks to JitPack: https://jitpack.io/
- implementation 'com.github.TeamNewPipe:nanojson:e9d656ddb49a412a5a0a5d5ef20ca7ef09549996'
- // WORKAROUND: if you get errors with the NewPipeExtractor dependency, replace `v0.24.3` with
- // the corresponding commit hash, since JitPack sometimes deletes artifacts.
- // If there’s already a git hash, just add more of it to the end (or remove a letter)
- // to cause jitpack to regenerate the artifact.
- implementation 'com.github.TeamNewPipe:NewPipeExtractor:v0.24.8'
- implementation 'com.github.TeamNewPipe:NoNonsense-FilePicker:5.0.0'
-
-/** Checkstyle **/
- checkstyle "com.puppycrawl.tools:checkstyle:${checkstyleVersion}"
- ktlint 'com.pinterest:ktlint:0.45.2'
-
-/** Kotlin **/
- implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}"
-
-/** AndroidX **/
- implementation 'androidx.appcompat:appcompat:1.7.1'
- implementation 'androidx.cardview:cardview:1.0.0'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
- implementation 'androidx.core:core-ktx:1.12.0'
- implementation 'androidx.documentfile:documentfile:1.0.1'
- implementation 'androidx.fragment:fragment-ktx:1.6.2'
- implementation "androidx.lifecycle:lifecycle-livedata-ktx:${androidxLifecycleVersion}"
- implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${androidxLifecycleVersion}"
- implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
- implementation 'androidx.media:media:1.7.0'
- implementation 'androidx.preference:preference:1.2.1'
- implementation 'androidx.recyclerview:recyclerview:1.3.2'
- implementation "androidx.room:room-runtime:${androidxRoomVersion}"
- implementation "androidx.room:room-rxjava3:${androidxRoomVersion}"
- kapt "androidx.room:room-compiler:${androidxRoomVersion}"
- implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
- // Newer version specified to prevent accessibility regressions with RecyclerView, see:
- // https://developer.android.com/jetpack/androidx/releases/viewpager2#1.1.0-alpha01
- implementation 'androidx.viewpager2:viewpager2:1.1.0-beta02'
- implementation "androidx.work:work-runtime-ktx:${androidxWorkVersion}"
- implementation "androidx.work:work-rxjava3:${androidxWorkVersion}"
- implementation 'com.google.android.material:material:1.11.0'
- implementation "androidx.webkit:webkit:1.9.0"
-
-/** Third-party libraries **/
- // Instance state boilerplate elimination
- implementation 'com.github.livefront:bridge:v2.0.2'
- implementation "com.evernote:android-state:$stateSaverVersion"
- kapt "com.evernote:android-state-processor:$stateSaverVersion"
-
- // HTML parser
- implementation "org.jsoup:jsoup:1.17.2"
-
- // HTTP client
- implementation "com.squareup.okhttp3:okhttp:4.12.0"
-
- // Media player
- implementation "com.google.android.exoplayer:exoplayer-core:${exoPlayerVersion}"
- implementation "com.google.android.exoplayer:exoplayer-dash:${exoPlayerVersion}"
- implementation "com.google.android.exoplayer:exoplayer-database:${exoPlayerVersion}"
- implementation "com.google.android.exoplayer:exoplayer-datasource:${exoPlayerVersion}"
- implementation "com.google.android.exoplayer:exoplayer-hls:${exoPlayerVersion}"
- implementation "com.google.android.exoplayer:exoplayer-smoothstreaming:${exoPlayerVersion}"
- implementation "com.google.android.exoplayer:exoplayer-ui:${exoPlayerVersion}"
- implementation "com.google.android.exoplayer:extension-mediasession:${exoPlayerVersion}"
-
- // Metadata generator for service descriptors
- compileOnly "com.google.auto.service:auto-service-annotations:${googleAutoServiceVersion}"
- kapt "com.google.auto.service:auto-service:${googleAutoServiceVersion}"
-
- // Manager for complex RecyclerView layouts
- implementation "com.github.lisawray.groupie:groupie:${groupieVersion}"
- implementation "com.github.lisawray.groupie:groupie-viewbinding:${groupieVersion}"
-
- // Image loading
- //noinspection GradleDependency --> 2.8 is the last version, not 2.71828!
- implementation "com.squareup.picasso:picasso:2.8"
-
- // Markdown library for Android
- implementation "io.noties.markwon:core:${markwonVersion}"
- implementation "io.noties.markwon:linkify:${markwonVersion}"
-
- // Crash reporting
- implementation "ch.acra:acra-core:5.11.3"
-
- // Properly restarting
- implementation 'com.jakewharton:process-phoenix:2.1.2'
-
- // Reactive extensions for Java VM
- implementation "io.reactivex.rxjava3:rxjava:3.1.8"
- implementation "io.reactivex.rxjava3:rxandroid:3.0.2"
- // RxJava binding APIs for Android UI widgets
- implementation "com.jakewharton.rxbinding4:rxbinding:4.0.0"
-
- // Date and time formatting
- implementation "org.ocpsoft.prettytime:prettytime:5.0.8.Final"
-
-/** Debugging **/
- // Memory leak detection
- debugImplementation "com.squareup.leakcanary:leakcanary-object-watcher-android:${leakCanaryVersion}"
- debugImplementation "com.squareup.leakcanary:plumber-android:${leakCanaryVersion}"
- debugImplementation "com.squareup.leakcanary:leakcanary-android-core:${leakCanaryVersion}"
- // Debug bridge for Android
- debugImplementation "com.facebook.stetho:stetho:${stethoVersion}"
- debugImplementation "com.facebook.stetho:stetho-okhttp3:${stethoVersion}"
-
-/** Testing **/
- testImplementation 'junit:junit:4.13.2'
- testImplementation 'org.mockito:mockito-core:5.6.0'
-
- androidTestImplementation "androidx.test.ext:junit:1.1.5"
- androidTestImplementation "androidx.test:runner:1.5.2"
- androidTestImplementation "androidx.room:room-testing:${androidxRoomVersion}"
- androidTestImplementation "org.assertj:assertj-core:3.24.2"
-}
-
-static String getGitWorkingBranch() {
- try {
- def gitProcess = "git rev-parse --abbrev-ref HEAD".execute()
- gitProcess.waitFor()
- if (gitProcess.exitValue() == 0) {
- return gitProcess.text.trim()
- } else {
- // not a git repository
- return ""
- }
- } catch (IOException ignored) {
- // git was not found
- return ""
- }
-}
-
-// fix reproducible builds
-project.afterEvaluate {
- tasks.compileReleaseArtProfile.doLast {
- outputs.files.each { file ->
- if (file.toString().endsWith(".profm")) {
- println("Sorting ${file} ...")
- def version = ArtProfileSerializer.valueOf("METADATA_0_0_2")
- def profile = ArtProfileKt.ArtProfile(file)
- def keys = new ArrayList(profile.profileData.keySet())
- def sortedData = new LinkedHashMap()
- Collections.sort keys, new DexFile.Companion()
- keys.each { key -> sortedData[key] = profile.profileData[key] }
- new FileOutputStream(file).with {
- write(version.magicBytes$profgen)
- write(version.versionBytes$profgen)
- version.write$profgen(it, sortedData, "")
- }
- }
- }
- }
-}
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
new file mode 100644
index 000000000..1aa5297c5
--- /dev/null
+++ b/app/build.gradle.kts
@@ -0,0 +1,306 @@
+/*
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+plugins {
+ alias(libs.plugins.android.application)
+ alias(libs.plugins.jetbrains.kotlin.android)
+ alias(libs.plugins.jetbrains.kotlin.kapt)
+ alias(libs.plugins.google.ksp)
+ alias(libs.plugins.jetbrains.kotlin.parcelize)
+ alias(libs.plugins.sonarqube)
+ checkstyle
+}
+
+val gitWorkingBranch = providers.exec {
+ commandLine("git", "rev-parse", "--abbrev-ref", "HEAD")
+}.standardOutput.asText.map { it.trim() }
+
+java {
+ toolchain {
+ languageVersion = JavaLanguageVersion.of(17)
+ }
+}
+
+kotlin {
+ compilerOptions {
+ // TODO: Drop annotation default target when it is stable
+ freeCompilerArgs.addAll(
+ "-Xannotation-default-target=param-property"
+ )
+ }
+}
+
+android {
+ compileSdk = 36
+ namespace = "org.schabi.newpipe"
+
+ defaultConfig {
+ applicationId = "org.schabi.newpipe"
+ resValue("string", "app_name", "NewPipe")
+ minSdk = 21
+ targetSdk = 35
+
+ versionCode = System.getProperty("versionCodeOverride")?.toInt() ?: 1006
+
+ versionName = "0.28.1"
+ System.getProperty("versionNameSuffix")?.let { versionNameSuffix = it }
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ debug {
+ isDebuggable = true
+
+ // suffix the app id and the app name with git branch name
+ val defaultBranches = listOf("master", "dev")
+ val workingBranch = gitWorkingBranch.getOrElse("")
+ val normalizedWorkingBranch = workingBranch
+ .replaceFirst("^[^A-Za-z]+".toRegex(), "")
+ .replace("[^0-9A-Za-z]+".toRegex(), "")
+
+ if (normalizedWorkingBranch.isEmpty() || workingBranch in defaultBranches) {
+ // default values when branch name could not be determined or is master or dev
+ applicationIdSuffix = ".debug"
+ resValue("string", "app_name", "NewPipe Debug")
+ } else {
+ applicationIdSuffix = ".debug.$normalizedWorkingBranch"
+ resValue("string", "app_name", "NewPipe $workingBranch")
+ }
+ }
+
+ release {
+ System.getProperty("packageSuffix")?.let { suffix ->
+ applicationIdSuffix = suffix
+ resValue("string", "app_name", "NewPipe $suffix")
+ }
+ isMinifyEnabled = true
+ isShrinkResources = false // disabled to fix F-Droid"s reproducible build
+ proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
+ }
+ }
+
+ lint {
+ checkReleaseBuilds = false
+ // Or, if you prefer, you can continue to check for errors in release builds,
+ // but continue the build even when errors are found:
+ abortOnError = false
+ // suppress false warning ("Resource IDs will be non-final in Android Gradle Plugin version
+ // 5.0, avoid using them in switch case statements"), which affects only library projects
+ disable += "NonConstantResourceId"
+ }
+
+ compileOptions {
+ // Flag to enable support for the new language APIs
+ isCoreLibraryDesugaringEnabled = true
+ encoding = "utf-8"
+ }
+
+ sourceSets {
+ getByName("androidTest") {
+ assets.srcDir("$projectDir/schemas")
+ }
+ }
+
+ androidResources {
+ generateLocaleConfig = true
+ }
+
+ buildFeatures {
+ viewBinding = true
+ buildConfig = true
+ }
+
+ packaging {
+ resources {
+ // remove two files which belong to jsoup
+ // no idea how they ended up in the META-INF dir...
+ excludes += setOf(
+ "META-INF/README.md",
+ "META-INF/CHANGES",
+ "META-INF/COPYRIGHT" // "COPYRIGHT" belongs to RxJava...
+ )
+ }
+ }
+}
+
+ksp {
+ arg("room.schemaLocation", "$projectDir/schemas")
+}
+
+
+// Custom dependency configuration for ktlint
+val ktlint by configurations.creating
+
+checkstyle {
+ configDirectory = rootProject.file("checkstyle")
+ isIgnoreFailures = false
+ isShowViolations = true
+ toolVersion = libs.versions.checkstyle.get()
+}
+
+tasks.register("runCheckstyle") {
+ source("src")
+ include("**/*.java")
+ exclude("**/gen/**")
+ exclude("**/R.java")
+ exclude("**/BuildConfig.java")
+ exclude("main/java/us/shandian/giga/**")
+
+ classpath = configurations.getByName("checkstyle")
+
+ isShowViolations = true
+
+ reports {
+ xml.required = true
+ html.required = true
+ }
+}
+
+val outputDir = project.layout.buildDirectory.dir("reports/ktlint/")
+val inputFiles = fileTree("src") { include("**/*.kt") }
+
+tasks.register("runKtlint") {
+ inputs.files(inputFiles)
+ outputs.dir(outputDir)
+ mainClass.set("com.pinterest.ktlint.Main")
+ classpath = configurations.getByName("ktlint")
+ args = listOf("--editorconfig=../.editorconfig", "src/**/*.kt")
+ jvmArgs = listOf("--add-opens", "java.base/java.lang=ALL-UNNAMED")
+}
+
+tasks.register("formatKtlint") {
+ inputs.files(inputFiles)
+ outputs.dir(outputDir)
+ mainClass.set("com.pinterest.ktlint.Main")
+ classpath = configurations.getByName("ktlint")
+ args = listOf("--editorconfig=../.editorconfig", "-F", "src/**/*.kt")
+ jvmArgs = listOf("--add-opens", "java.base/java.lang=ALL-UNNAMED")
+}
+
+tasks.register("checkDependenciesOrder") {
+ tomlFile = layout.projectDirectory.file("../gradle/libs.versions.toml")
+}
+
+afterEvaluate {
+ tasks.named("preDebugBuild").configure {
+ if (!System.getProperties().containsKey("skipFormatKtlint")) {
+ dependsOn("formatKtlint")
+ }
+ dependsOn("runCheckstyle", "runKtlint", "checkDependenciesOrder")
+ }
+}
+
+sonar {
+ properties {
+ property("sonar.projectKey", "TeamNewPipe_NewPipe")
+ property("sonar.organization", "teamnewpipe")
+ property("sonar.host.url", "https://sonarcloud.io")
+ }
+}
+
+dependencies {
+ /** Desugaring **/
+ coreLibraryDesugaring(libs.android.desugar)
+
+ /** NewPipe libraries **/
+ implementation(libs.newpipe.nanojson)
+ implementation(libs.newpipe.extractor)
+ implementation(libs.newpipe.filepicker)
+
+ /** Checkstyle **/
+ checkstyle(libs.puppycrawl.checkstyle)
+ ktlint(libs.pinterest.ktlint)
+
+ /** AndroidX **/
+ implementation(libs.androidx.appcompat)
+ implementation(libs.androidx.cardview)
+ implementation(libs.androidx.constraintlayout)
+ implementation(libs.androidx.core)
+ implementation(libs.androidx.documentfile)
+ implementation(libs.androidx.fragment)
+ implementation(libs.androidx.lifecycle.livedata)
+ implementation(libs.androidx.lifecycle.viewmodel)
+ implementation(libs.androidx.localbroadcastmanager)
+ implementation(libs.androidx.media)
+ implementation(libs.androidx.preference)
+ implementation(libs.androidx.recyclerview)
+ implementation(libs.androidx.room.runtime)
+ implementation(libs.androidx.room.rxjava3)
+ ksp(libs.androidx.room.compiler)
+ implementation(libs.androidx.swiperefreshlayout)
+ implementation(libs.androidx.viewpager2)
+ implementation(libs.androidx.work.runtime)
+ implementation(libs.androidx.work.rxjava3)
+ implementation(libs.google.android.material)
+ implementation(libs.androidx.webkit)
+
+ /** Third-party libraries **/
+ implementation(libs.livefront.bridge)
+ implementation(libs.evernote.statesaver.core)
+ kapt(libs.evernote.statesaver.compiler)
+
+ // HTML parser
+ implementation(libs.jsoup)
+
+ // HTTP client
+ implementation(libs.squareup.okhttp)
+
+ // Media player
+ implementation(libs.google.exoplayer.core)
+ implementation(libs.google.exoplayer.dash)
+ implementation(libs.google.exoplayer.database)
+ implementation(libs.google.exoplayer.datasource)
+ implementation(libs.google.exoplayer.hls)
+ implementation(libs.google.exoplayer.mediasession)
+ implementation(libs.google.exoplayer.smoothstreaming)
+ implementation(libs.google.exoplayer.ui)
+
+ // Manager for complex RecyclerView layouts
+ implementation(libs.lisawray.groupie.core)
+ implementation(libs.lisawray.groupie.viewbinding)
+
+ // Image loading
+ implementation(libs.squareup.picasso)
+
+ // Markdown library for Android
+ implementation(libs.noties.markwon.core)
+ implementation(libs.noties.markwon.linkify)
+
+ // Crash reporting
+ implementation(libs.acra.core)
+ compileOnly(libs.google.autoservice.annotations)
+ ksp(libs.zacsweers.autoservice.compiler)
+
+ // Properly restarting
+ implementation(libs.jakewharton.phoenix)
+
+ // Reactive extensions for Java VM
+ implementation(libs.reactivex.rxjava)
+ implementation(libs.reactivex.rxandroid)
+ // RxJava binding APIs for Android UI widgets
+ implementation(libs.jakewharton.rxbinding)
+
+ // Date and time formatting
+ implementation(libs.ocpsoft.prettytime)
+
+ /** Debugging **/
+ // Memory leak detection
+ debugImplementation(libs.squareup.leakcanary.watcher)
+ debugImplementation(libs.squareup.leakcanary.plumber)
+ debugImplementation(libs.squareup.leakcanary.core)
+ // Debug bridge for Android
+ debugImplementation(libs.facebook.stetho.core)
+ debugImplementation(libs.facebook.stetho.okhttp3)
+
+ /** Testing **/
+ testImplementation(libs.junit)
+ testImplementation(libs.mockito.core)
+
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.runner)
+ androidTestImplementation(libs.androidx.room.testing)
+ androidTestImplementation(libs.assertj.core)
+}
diff --git a/app/schemas/org.schabi.newpipe.database.AppDatabase/9.json b/app/schemas/org.schabi.newpipe.database.AppDatabase/9.json
index aced06c0a..b9a618638 100644
--- a/app/schemas/org.schabi.newpipe.database.AppDatabase/9.json
+++ b/app/schemas/org.schabi.newpipe.database.AppDatabase/9.json
@@ -458,7 +458,7 @@
"notNull": true
},
{
- "fieldPath": "name",
+ "fieldPath": "orderingName",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
diff --git a/app/src/androidTest/java/org/schabi/newpipe/database/DatabaseMigrationTest.kt b/app/src/androidTest/java/org/schabi/newpipe/database/DatabaseMigrationTest.kt
index a34cfece6..4327271f4 100644
--- a/app/src/androidTest/java/org/schabi/newpipe/database/DatabaseMigrationTest.kt
+++ b/app/src/androidTest/java/org/schabi/newpipe/database/DatabaseMigrationTest.kt
@@ -129,7 +129,7 @@ class DatabaseMigrationTest {
)
val migratedDatabaseV3 = getMigratedDatabase()
- val listFromDB = migratedDatabaseV3.streamDAO().all.blockingFirst()
+ val listFromDB = migratedDatabaseV3.streamDAO().getAll().blockingFirst()
// Only expect 2, the one with the null url will be ignored
assertEquals(2, listFromDB.size)
@@ -217,7 +217,7 @@ class DatabaseMigrationTest {
)
val migratedDatabaseV8 = getMigratedDatabase()
- val listFromDB = migratedDatabaseV8.searchHistoryDAO().all.blockingFirst()
+ val listFromDB = migratedDatabaseV8.searchHistoryDAO().getAll().blockingFirst()
assertEquals(2, listFromDB.size)
assertEquals("abc", listFromDB[0].search)
@@ -283,8 +283,8 @@ class DatabaseMigrationTest {
)
val migratedDatabaseV9 = getMigratedDatabase()
- var localListFromDB = migratedDatabaseV9.playlistDAO().all.blockingFirst()
- var remoteListFromDB = migratedDatabaseV9.playlistRemoteDAO().all.blockingFirst()
+ var localListFromDB = migratedDatabaseV9.playlistDAO().getAll().blockingFirst()
+ var remoteListFromDB = migratedDatabaseV9.playlistRemoteDAO().getAll().blockingFirst()
assertEquals(1, localListFromDB.size)
assertEquals(localUid2, localListFromDB[0].uid)
@@ -294,17 +294,27 @@ class DatabaseMigrationTest {
assertEquals(-1, remoteListFromDB[0].displayIndex)
val localUid3 = migratedDatabaseV9.playlistDAO().insert(
- PlaylistEntity(DEFAULT_NAME + "3", false, -1, -1)
+ PlaylistEntity(
+ name = "${DEFAULT_NAME}3",
+ isThumbnailPermanent = false,
+ thumbnailStreamId = -1,
+ displayIndex = -1
+ )
)
val remoteUid3 = migratedDatabaseV9.playlistRemoteDAO().insert(
PlaylistRemoteEntity(
- DEFAULT_THIRD_SERVICE_ID, DEFAULT_NAME, DEFAULT_THIRD_URL,
- DEFAULT_THUMBNAIL, DEFAULT_UPLOADER_NAME, -1, 10
+ serviceId = DEFAULT_THIRD_SERVICE_ID,
+ orderingName = DEFAULT_NAME,
+ url = DEFAULT_THIRD_URL,
+ thumbnailUrl = DEFAULT_THUMBNAIL,
+ uploader = DEFAULT_UPLOADER_NAME,
+ displayIndex = -1,
+ streamCount = 10
)
)
- localListFromDB = migratedDatabaseV9.playlistDAO().all.blockingFirst()
- remoteListFromDB = migratedDatabaseV9.playlistRemoteDAO().all.blockingFirst()
+ localListFromDB = migratedDatabaseV9.playlistDAO().getAll().blockingFirst()
+ remoteListFromDB = migratedDatabaseV9.playlistRemoteDAO().getAll().blockingFirst()
assertEquals(2, localListFromDB.size)
assertEquals(localUid3, localListFromDB[1].uid)
assertEquals(-1, localListFromDB[1].displayIndex)
diff --git a/app/src/androidTest/java/org/schabi/newpipe/error/ErrorInfoTest.java b/app/src/androidTest/java/org/schabi/newpipe/error/ErrorInfoTest.java
index 891824a55..892d1df0f 100644
--- a/app/src/androidTest/java/org/schabi/newpipe/error/ErrorInfoTest.java
+++ b/app/src/androidTest/java/org/schabi/newpipe/error/ErrorInfoTest.java
@@ -12,6 +12,7 @@ import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import java.util.Arrays;
+import java.util.Objects;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -23,8 +24,23 @@ import static org.junit.Assert.assertTrue;
@LargeTest
public class ErrorInfoTest {
+ /**
+ * @param errorInfo the error info to access
+ * @return the private field errorInfo.message.stringRes using reflection
+ */
+ private int getMessageFromErrorInfo(final ErrorInfo errorInfo)
+ throws NoSuchFieldException, IllegalAccessException {
+ final var message = ErrorInfo.class.getDeclaredField("message");
+ message.setAccessible(true);
+ final var messageValue = (ErrorInfo.Companion.ErrorMessage) message.get(errorInfo);
+
+ final var stringRes = ErrorInfo.Companion.ErrorMessage.class.getDeclaredField("stringRes");
+ stringRes.setAccessible(true);
+ return (int) Objects.requireNonNull(stringRes.get(messageValue));
+ }
+
@Test
- public void errorInfoTestParcelable() {
+ public void errorInfoTestParcelable() throws NoSuchFieldException, IllegalAccessException {
final ErrorInfo info = new ErrorInfo(new ParsingException("Hello"),
UserAction.USER_REPORT, "request", ServiceList.YouTube.getServiceId());
// Obtain a Parcel object and write the parcelable object to it:
@@ -39,7 +55,7 @@ public class ErrorInfoTest {
assertEquals(ServiceList.YouTube.getServiceInfo().getName(),
infoFromParcel.getServiceName());
assertEquals("request", infoFromParcel.getRequest());
- assertEquals(R.string.parsing_error, infoFromParcel.getMessageStringId());
+ assertEquals(R.string.parsing_error, getMessageFromErrorInfo(infoFromParcel));
parcel.recycle();
}
diff --git a/app/src/androidTest/java/org/schabi/newpipe/local/history/HistoryRecordManagerTest.kt b/app/src/androidTest/java/org/schabi/newpipe/local/history/HistoryRecordManagerTest.kt
index 24be0f868..0de9dd268 100644
--- a/app/src/androidTest/java/org/schabi/newpipe/local/history/HistoryRecordManagerTest.kt
+++ b/app/src/androidTest/java/org/schabi/newpipe/local/history/HistoryRecordManagerTest.kt
@@ -41,7 +41,7 @@ class HistoryRecordManagerTest {
// For some reason the Flowable returned by getAll() never completes, so we can't assert
// that the number of Lists it returns is exactly 1, we can only check if the first List is
// correct. Why on earth has a Flowable been used instead of a Single for getAll()?!?
- val entities = database.searchHistoryDAO().all.blockingFirst()
+ val entities = database.searchHistoryDAO().getAll().blockingFirst()
assertThat(entities).hasSize(1)
assertThat(entities[0].id).isEqualTo(1)
assertThat(entities[0].serviceId).isEqualTo(0)
@@ -51,50 +51,50 @@ class HistoryRecordManagerTest {
@Test
fun deleteSearchHistory() {
val entries = listOf(
- SearchHistoryEntry(time.minusSeconds(1), 0, "A"),
- SearchHistoryEntry(time.minusSeconds(2), 2, "A"),
- SearchHistoryEntry(time.minusSeconds(3), 1, "B"),
- SearchHistoryEntry(time.minusSeconds(4), 0, "B"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(1), serviceId = 0, search = "A"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(2), serviceId = 2, search = "A"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(3), serviceId = 1, search = "B"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(4), serviceId = 0, search = "B"),
)
// make sure all 4 were inserted
database.searchHistoryDAO().insertAll(entries)
- assertThat(database.searchHistoryDAO().all.blockingFirst()).hasSameSizeAs(entries)
+ assertThat(database.searchHistoryDAO().getAll().blockingFirst()).hasSameSizeAs(entries)
// try to delete only "A" entries, "B" entries should be untouched
manager.deleteSearchHistory("A").test().await().assertValue(2)
- val entities = database.searchHistoryDAO().all.blockingFirst()
+ val entities = database.searchHistoryDAO().getAll().blockingFirst()
assertThat(entities).hasSize(2)
assertThat(entities).usingElementComparator { o1, o2 -> if (o1.hasEqualValues(o2)) 0 else 1 }
.containsExactly(*entries.subList(2, 4).toTypedArray())
// assert that nothing happens if we delete a search query that does exist in the db
manager.deleteSearchHistory("A").test().await().assertValue(0)
- val entities2 = database.searchHistoryDAO().all.blockingFirst()
+ val entities2 = database.searchHistoryDAO().getAll().blockingFirst()
assertThat(entities2).hasSize(2)
assertThat(entities2).usingElementComparator { o1, o2 -> if (o1.hasEqualValues(o2)) 0 else 1 }
.containsExactly(*entries.subList(2, 4).toTypedArray())
// delete all remaining entries
manager.deleteSearchHistory("B").test().await().assertValue(2)
- assertThat(database.searchHistoryDAO().all.blockingFirst()).isEmpty()
+ assertThat(database.searchHistoryDAO().getAll().blockingFirst()).isEmpty()
}
@Test
fun deleteCompleteSearchHistory() {
val entries = listOf(
- SearchHistoryEntry(time.minusSeconds(1), 1, "A"),
- SearchHistoryEntry(time.minusSeconds(2), 2, "B"),
- SearchHistoryEntry(time.minusSeconds(3), 0, "C"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(1), serviceId = 1, search = "A"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(2), serviceId = 2, search = "B"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(3), serviceId = 0, search = "C"),
)
// make sure all 3 were inserted
database.searchHistoryDAO().insertAll(entries)
- assertThat(database.searchHistoryDAO().all.blockingFirst()).hasSameSizeAs(entries)
+ assertThat(database.searchHistoryDAO().getAll().blockingFirst()).hasSameSizeAs(entries)
// should remove everything
manager.deleteCompleteSearchHistory().test().await().assertValue(entries.size)
- assertThat(database.searchHistoryDAO().all.blockingFirst()).isEmpty()
+ assertThat(database.searchHistoryDAO().getAll().blockingFirst()).isEmpty()
}
private fun insertShuffledRelatedSearches(relatedSearches: Collection) {
@@ -107,7 +107,7 @@ class HistoryRecordManagerTest {
// make sure all entries were inserted
assertEquals(
relatedSearches.size,
- database.searchHistoryDAO().all.blockingFirst().size
+ database.searchHistoryDAO().getAll().blockingFirst().size
)
}
@@ -127,19 +127,18 @@ class HistoryRecordManagerTest {
@Test
fun getRelatedSearches_emptyQuery_manyDuplicates() {
- insertShuffledRelatedSearches(
- listOf(
- SearchHistoryEntry(time.minusSeconds(9), 3, "A"),
- SearchHistoryEntry(time.minusSeconds(8), 3, "AB"),
- SearchHistoryEntry(time.minusSeconds(7), 3, "A"),
- SearchHistoryEntry(time.minusSeconds(6), 3, "A"),
- SearchHistoryEntry(time.minusSeconds(5), 3, "BA"),
- SearchHistoryEntry(time.minusSeconds(4), 3, "A"),
- SearchHistoryEntry(time.minusSeconds(3), 3, "A"),
- SearchHistoryEntry(time.minusSeconds(2), 0, "A"),
- SearchHistoryEntry(time.minusSeconds(1), 2, "AA"),
- )
+ val relatedSearches = listOf(
+ SearchHistoryEntry(creationDate = time.minusSeconds(9), serviceId = 3, search = "A"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(8), serviceId = 3, search = "AB"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(7), serviceId = 3, search = "A"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(6), serviceId = 3, search = "A"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(5), serviceId = 3, search = "BA"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(4), serviceId = 3, search = "A"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(3), serviceId = 3, search = "A"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(2), serviceId = 0, search = "A"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(1), serviceId = 2, search = "AA"),
)
+ insertShuffledRelatedSearches(relatedSearches)
val searches = manager.getRelatedSearches("", 9, 3).blockingFirst()
assertThat(searches).containsExactly("AA", "A", "BA")
@@ -166,13 +165,13 @@ class HistoryRecordManagerTest {
private val time = OffsetDateTime.of(LocalDateTime.of(2000, 1, 1, 1, 1), ZoneOffset.UTC)
private val RELATED_SEARCHES_ENTRIES = listOf(
- SearchHistoryEntry(time.minusSeconds(7), 2, "AC"),
- SearchHistoryEntry(time.minusSeconds(6), 0, "ABC"),
- SearchHistoryEntry(time.minusSeconds(5), 1, "BA"),
- SearchHistoryEntry(time.minusSeconds(4), 3, "A"),
- SearchHistoryEntry(time.minusSeconds(2), 0, "B"),
- SearchHistoryEntry(time.minusSeconds(3), 2, "AA"),
- SearchHistoryEntry(time.minusSeconds(1), 1, "A"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(7), serviceId = 2, search = "AC"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(6), serviceId = 0, search = "ABC"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(5), serviceId = 1, search = "BA"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(4), serviceId = 3, search = "A"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(2), serviceId = 0, search = "B"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(3), serviceId = 2, search = "AA"),
+ SearchHistoryEntry(creationDate = time.minusSeconds(1), serviceId = 1, search = "A"),
)
}
}
diff --git a/app/src/androidTest/java/org/schabi/newpipe/local/playlist/LocalPlaylistManagerTest.kt b/app/src/androidTest/java/org/schabi/newpipe/local/playlist/LocalPlaylistManagerTest.kt
index c392d8d3d..ce3aeb84a 100644
--- a/app/src/androidTest/java/org/schabi/newpipe/local/playlist/LocalPlaylistManagerTest.kt
+++ b/app/src/androidTest/java/org/schabi/newpipe/local/playlist/LocalPlaylistManagerTest.kt
@@ -72,6 +72,6 @@ class LocalPlaylistManagerTest {
val result = manager.createPlaylist("name", listOf(stream, upserted))
result.test().await().assertComplete()
- database.streamDAO().all.test().awaitCount(1).assertValue(listOf(stream, upserted))
+ database.streamDAO().getAll().test().awaitCount(1).assertValue(listOf(stream, upserted))
}
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e0abd977b..20e9a6ca9 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -9,6 +9,8 @@
+
+
@@ -94,9 +96,22 @@
android:exported="false"
android:label="@string/title_activity_about" />
-
-
-
+
+
+
+
+
+
+
-
+
+
@@ -368,6 +385,7 @@
+
@@ -421,6 +439,7 @@
diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java
index a8827c33e..cf41aad46 100644
--- a/app/src/main/java/org/schabi/newpipe/App.java
+++ b/app/src/main/java/org/schabi/newpipe/App.java
@@ -65,6 +65,8 @@ public class App extends Application {
private static final String TAG = App.class.toString();
private boolean isFirstRun = false;
+ private boolean notificationsRequested = false;
+
private static App app;
@NonNull
@@ -72,6 +74,14 @@ public class App extends Application {
return app;
}
+ public boolean getNotificationsRequested() {
+ return notificationsRequested;
+ }
+
+ public void setNotificationsRequested() {
+ notificationsRequested = true;
+ }
+
@Override
protected void attachBaseContext(final Context base) {
super.attachBaseContext(base);
diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java
index 4fbd562b4..8dac39682 100644
--- a/app/src/main/java/org/schabi/newpipe/MainActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java
@@ -48,6 +48,7 @@ import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
@@ -896,7 +897,8 @@ public class MainActivity extends AppCompatActivity {
};
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(VideoDetailFragment.ACTION_PLAYER_STARTED);
- registerReceiver(broadcastReceiver, intentFilter);
+ ContextCompat.registerReceiver(this, broadcastReceiver, intentFilter,
+ ContextCompat.RECEIVER_EXPORTED);
// If the PlayerHolder is not bound yet, but the service is running, try to bind to it.
// Once the connection is established, the ACTION_PLAYER_STARTED will be sent.
diff --git a/app/src/main/java/org/schabi/newpipe/NewPipeDatabase.java b/app/src/main/java/org/schabi/newpipe/NewPipeDatabase.java
deleted file mode 100644
index 21c5354f4..000000000
--- a/app/src/main/java/org/schabi/newpipe/NewPipeDatabase.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.schabi.newpipe;
-
-import static org.schabi.newpipe.database.AppDatabase.DATABASE_NAME;
-import static org.schabi.newpipe.database.Migrations.MIGRATION_1_2;
-import static org.schabi.newpipe.database.Migrations.MIGRATION_2_3;
-import static org.schabi.newpipe.database.Migrations.MIGRATION_3_4;
-import static org.schabi.newpipe.database.Migrations.MIGRATION_4_5;
-import static org.schabi.newpipe.database.Migrations.MIGRATION_5_6;
-import static org.schabi.newpipe.database.Migrations.MIGRATION_6_7;
-import static org.schabi.newpipe.database.Migrations.MIGRATION_7_8;
-import static org.schabi.newpipe.database.Migrations.MIGRATION_8_9;
-
-import android.content.Context;
-import android.database.Cursor;
-
-import androidx.annotation.NonNull;
-import androidx.room.Room;
-
-import org.schabi.newpipe.database.AppDatabase;
-
-public final class NewPipeDatabase {
- private static volatile AppDatabase databaseInstance;
-
- private NewPipeDatabase() {
- //no instance
- }
-
- private static AppDatabase getDatabase(final Context context) {
- return Room
- .databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME)
- .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5,
- MIGRATION_5_6, MIGRATION_6_7, MIGRATION_7_8, MIGRATION_8_9)
- .build();
- }
-
- @NonNull
- public static AppDatabase getInstance(@NonNull final Context context) {
- AppDatabase result = databaseInstance;
- if (result == null) {
- synchronized (NewPipeDatabase.class) {
- result = databaseInstance;
- if (result == null) {
- databaseInstance = getDatabase(context);
- result = databaseInstance;
- }
- }
- }
-
- return result;
- }
-
- public static void checkpoint() {
- if (databaseInstance == null) {
- throw new IllegalStateException("database is not initialized");
- }
- final Cursor c = databaseInstance.query("pragma wal_checkpoint(full)", null);
- if (c.moveToFirst() && c.getInt(0) == 1) {
- throw new RuntimeException("Checkpoint was blocked from completing");
- }
- }
-
- public static void close() {
- if (databaseInstance != null) {
- synchronized (NewPipeDatabase.class) {
- if (databaseInstance != null) {
- databaseInstance.close();
- databaseInstance = null;
- }
- }
- }
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/NewPipeDatabase.kt b/app/src/main/java/org/schabi/newpipe/NewPipeDatabase.kt
new file mode 100644
index 000000000..c3ce51524
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/NewPipeDatabase.kt
@@ -0,0 +1,80 @@
+/*
+ * SPDX-FileCopyrightText: 2017-2024 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe
+
+import android.content.Context
+import androidx.room.Room.databaseBuilder
+import org.schabi.newpipe.database.AppDatabase
+import org.schabi.newpipe.database.Migrations.MIGRATION_1_2
+import org.schabi.newpipe.database.Migrations.MIGRATION_2_3
+import org.schabi.newpipe.database.Migrations.MIGRATION_3_4
+import org.schabi.newpipe.database.Migrations.MIGRATION_4_5
+import org.schabi.newpipe.database.Migrations.MIGRATION_5_6
+import org.schabi.newpipe.database.Migrations.MIGRATION_6_7
+import org.schabi.newpipe.database.Migrations.MIGRATION_7_8
+import org.schabi.newpipe.database.Migrations.MIGRATION_8_9
+import kotlin.concurrent.Volatile
+
+object NewPipeDatabase {
+
+ @Volatile
+ private var databaseInstance: AppDatabase? = null
+
+ private fun getDatabase(context: Context): AppDatabase {
+ return databaseBuilder(
+ context.applicationContext,
+ AppDatabase::class.java,
+ AppDatabase.Companion.DATABASE_NAME
+ ).addMigrations(
+ MIGRATION_1_2,
+ MIGRATION_2_3,
+ MIGRATION_3_4,
+ MIGRATION_4_5,
+ MIGRATION_5_6,
+ MIGRATION_6_7,
+ MIGRATION_7_8,
+ MIGRATION_8_9
+ ).build()
+ }
+
+ @JvmStatic
+ fun getInstance(context: Context): AppDatabase {
+ var result = databaseInstance
+ if (result == null) {
+ synchronized(NewPipeDatabase::class.java) {
+ result = databaseInstance
+ if (result == null) {
+ databaseInstance = getDatabase(context)
+ result = databaseInstance
+ }
+ }
+ }
+
+ return result!!
+ }
+
+ @JvmStatic
+ fun checkpoint() {
+ checkNotNull(databaseInstance) { "database is not initialized" }
+ val c = databaseInstance!!.query("pragma wal_checkpoint(full)", null)
+ if (c.moveToFirst() && c.getInt(0) == 1) {
+ throw RuntimeException("Checkpoint was blocked from completing")
+ }
+ }
+
+ @JvmStatic
+ fun close() {
+ if (databaseInstance != null) {
+ synchronized(NewPipeDatabase::class.java) {
+ if (databaseInstance != null) {
+ databaseInstance!!.close()
+ databaseInstance = null
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/RouterActivity.java b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
index 3294cae0b..d85fdf7de 100644
--- a/app/src/main/java/org/schabi/newpipe/RouterActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
@@ -58,20 +58,10 @@ import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.StreamingService.LinkType;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
-import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException;
-import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
-import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
-import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException;
-import org.schabi.newpipe.extractor.exceptions.PaidContentException;
-import org.schabi.newpipe.extractor.exceptions.PrivateContentException;
-import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
-import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException;
-import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfo;
-import org.schabi.newpipe.ktx.ExceptionUtils;
import org.schabi.newpipe.local.dialog.PlaylistDialog;
import org.schabi.newpipe.player.PlayerType;
import org.schabi.newpipe.player.helper.PlayerHelper;
@@ -260,7 +250,8 @@ public class RouterActivity extends AppCompatActivity {
showUnsupportedUrlDialog(url);
}
}, throwable -> handleError(this, new ErrorInfo(throwable,
- UserAction.SHARE_TO_NEWPIPE, "Getting service from url: " + url))));
+ UserAction.SHARE_TO_NEWPIPE, "Getting service from url: " + url,
+ null, url))));
}
/**
@@ -269,40 +260,19 @@ public class RouterActivity extends AppCompatActivity {
* @param errorInfo the error information
*/
private static void handleError(final Context context, final ErrorInfo errorInfo) {
- if (errorInfo.getThrowable() != null) {
- errorInfo.getThrowable().printStackTrace();
- }
-
- if (errorInfo.getThrowable() instanceof ReCaptchaException) {
+ if (errorInfo.getRecaptchaUrl() != null) {
Toast.makeText(context, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
// Starting ReCaptcha Challenge Activity
final Intent intent = new Intent(context, ReCaptchaActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(ReCaptchaActivity.RECAPTCHA_URL_EXTRA, errorInfo.getRecaptchaUrl());
context.startActivity(intent);
- } else if (errorInfo.getThrowable() != null
- && ExceptionUtils.isNetworkRelated(errorInfo.getThrowable())) {
- Toast.makeText(context, R.string.network_error, Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof AgeRestrictedContentException) {
- Toast.makeText(context, R.string.restricted_video_no_stream,
- Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof GeographicRestrictionException) {
- Toast.makeText(context, R.string.georestricted_content, Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof PaidContentException) {
- Toast.makeText(context, R.string.paid_content, Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof PrivateContentException) {
- Toast.makeText(context, R.string.private_content, Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof SoundCloudGoPlusContentException) {
- Toast.makeText(context, R.string.soundcloud_go_plus_content,
- Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof YoutubeMusicPremiumContentException) {
- Toast.makeText(context, R.string.youtube_music_premium_content,
- Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof ContentNotAvailableException) {
- Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show();
- } else if (errorInfo.getThrowable() instanceof ContentNotSupportedException) {
- Toast.makeText(context, R.string.content_not_supported, Toast.LENGTH_LONG).show();
- } else {
+ } else if (errorInfo.isReportable()) {
ErrorUtil.createNotification(context, errorInfo);
+ } else {
+ // this exception does not usually indicate a problem that should be reported,
+ // so just show a toast instead of the notification
+ Toast.makeText(context, errorInfo.getMessage(context), Toast.LENGTH_LONG).show();
}
if (context instanceof RouterActivity) {
@@ -346,7 +316,8 @@ public class RouterActivity extends AppCompatActivity {
if (choiceChecker.isAvailableAndSelected(
R.string.video_player_key,
R.string.background_player_key,
- R.string.popup_player_key)) {
+ R.string.popup_player_key,
+ R.string.enqueue_key)) {
final String selectedChoice = choiceChecker.getSelectedChoiceKey();
@@ -359,6 +330,8 @@ public class RouterActivity extends AppCompatActivity {
|| selectedChoice.equals(getString(R.string.popup_player_key));
final boolean isAudioPlayerSelected =
selectedChoice.equals(getString(R.string.background_player_key));
+ final boolean isEnqueueSelected =
+ selectedChoice.equals(getString(R.string.enqueue_key));
if (currentLinkType != LinkType.STREAM
&& ((isExtAudioEnabled && isAudioPlayerSelected)
@@ -375,7 +348,9 @@ public class RouterActivity extends AppCompatActivity {
// Check if the service supports the choice
if ((isVideoPlayerSelected && capabilities.contains(VIDEO))
- || (isAudioPlayerSelected && capabilities.contains(AUDIO))) {
+ || (isAudioPlayerSelected && capabilities.contains(AUDIO))
+ || (isEnqueueSelected && (capabilities.contains(VIDEO)
+ || capabilities.contains(AUDIO)))) {
handleChoice(selectedChoice);
} else {
handleChoice(getString(R.string.show_info_key));
@@ -556,7 +531,7 @@ public class RouterActivity extends AppCompatActivity {
final List capabilities =
service.getServiceInfo().getMediaCapabilities();
- if (linkType == LinkType.STREAM) {
+ if (linkType == LinkType.STREAM || linkType == LinkType.PLAYLIST) {
if (capabilities.contains(VIDEO)) {
returnedItems.add(videoPlayer);
returnedItems.add(popupPlayer);
@@ -564,17 +539,28 @@ public class RouterActivity extends AppCompatActivity {
if (capabilities.contains(AUDIO)) {
returnedItems.add(backgroundPlayer);
}
- // download is redundant for linkType CHANNEL AND PLAYLIST (till playlist downloading is
- // not supported )
- returnedItems.add(new AdapterChoiceItem(getString(R.string.download_key),
- getString(R.string.download),
- R.drawable.ic_file_download));
- // Add to playlist is not necessary for CHANNEL and PLAYLIST linkType since those can
- // not be added to a playlist
- returnedItems.add(new AdapterChoiceItem(getString(R.string.add_to_playlist_key),
- getString(R.string.add_to_playlist),
- R.drawable.ic_add));
+ // Enqueue is only shown if the current queue is not empty.
+ // However, if the playqueue or the player is cleared after this item was chosen and
+ // while the item is extracted, it will automatically fall back to background player.
+ if (PlayerHolder.getInstance().getQueueSize() > 0) {
+ returnedItems.add(new AdapterChoiceItem(getString(R.string.enqueue_key),
+ getString(R.string.enqueue_stream), R.drawable.ic_add));
+ }
+
+ if (linkType == LinkType.STREAM) {
+ // download is redundant for linkType CHANNEL AND PLAYLIST
+ // (till playlist downloading is not supported )
+ returnedItems.add(new AdapterChoiceItem(getString(R.string.download_key),
+ getString(R.string.download),
+ R.drawable.ic_file_download));
+
+ // Add to playlist is not necessary for CHANNEL and PLAYLIST linkType
+ // since those can not be added to a playlist
+ returnedItems.add(new AdapterChoiceItem(getString(R.string.add_to_playlist_key),
+ getString(R.string.add_to_playlist),
+ R.drawable.ic_playlist_add));
+ }
} else {
// LinkType.NONE is never present because it's filtered out before
// channels and playlist can be played as they contain a list of videos
@@ -665,7 +651,8 @@ public class RouterActivity extends AppCompatActivity {
startActivity(intent);
finish();
}, throwable -> handleError(this, new ErrorInfo(throwable,
- UserAction.SHARE_TO_NEWPIPE, "Starting info activity: " + currentUrl)))
+ UserAction.SHARE_TO_NEWPIPE, "Starting info activity: " + currentUrl,
+ null, currentUrl)))
);
return;
}
@@ -852,10 +839,10 @@ public class RouterActivity extends AppCompatActivity {
})
)),
throwable -> runOnVisible(ctx -> handleError(ctx, new ErrorInfo(
- throwable,
- UserAction.REQUESTED_STREAM,
+ throwable, UserAction.REQUESTED_STREAM,
"Tried to add " + currentUrl + " to a playlist",
- ((RouterActivity) ctx).currentService.getServiceId())
+ ((RouterActivity) ctx).currentService.getServiceId(),
+ currentUrl)
))
)
);
@@ -995,7 +982,7 @@ public class RouterActivity extends AppCompatActivity {
}
}, throwable -> handleError(this, new ErrorInfo(throwable, finalUserAction,
choice.url + " opened with " + choice.playerChoice,
- choice.serviceId)));
+ choice.serviceId, choice.url)));
}
}
@@ -1045,6 +1032,8 @@ public class RouterActivity extends AppCompatActivity {
NavigationHelper.playOnBackgroundPlayer(this, playQueue, true);
} else if (choice.playerChoice.equals(popupPlayerKey)) {
NavigationHelper.playOnPopupPlayer(this, playQueue, true);
+ } else if (choice.playerChoice.equals(getString(R.string.enqueue_key))) {
+ NavigationHelper.enqueueOnPlayer(this, playQueue);
}
};
}
diff --git a/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.kt b/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.kt
index 189fa148b..240e2f42b 100644
--- a/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.kt
+++ b/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.kt
@@ -7,6 +7,7 @@ import android.view.View
import android.view.ViewGroup
import android.webkit.WebView
import androidx.appcompat.app.AlertDialog
+import androidx.core.os.BundleCompat
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
@@ -33,7 +34,9 @@ class LicenseFragment : Fragment() {
super.onCreate(savedInstanceState)
softwareComponents = arguments?.parcelableArrayList(ARG_COMPONENTS)!!
.sortedBy { it.name } // Sort components by name
- activeSoftwareComponent = savedInstanceState?.getSerializable(SOFTWARE_COMPONENT_KEY) as? SoftwareComponent
+ activeSoftwareComponent = savedInstanceState?.let {
+ BundleCompat.getSerializable(it, SOFTWARE_COMPONENT_KEY, SoftwareComponent::class.java)
+ }
}
override fun onDestroy() {
diff --git a/app/src/main/java/org/schabi/newpipe/database/AppDatabase.java b/app/src/main/java/org/schabi/newpipe/database/AppDatabase.java
deleted file mode 100644
index 04d93a238..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/AppDatabase.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.schabi.newpipe.database;
-
-import static org.schabi.newpipe.database.Migrations.DB_VER_9;
-
-import androidx.room.Database;
-import androidx.room.RoomDatabase;
-import androidx.room.TypeConverters;
-
-import org.schabi.newpipe.database.feed.dao.FeedDAO;
-import org.schabi.newpipe.database.feed.dao.FeedGroupDAO;
-import org.schabi.newpipe.database.feed.model.FeedEntity;
-import org.schabi.newpipe.database.feed.model.FeedGroupEntity;
-import org.schabi.newpipe.database.feed.model.FeedGroupSubscriptionEntity;
-import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity;
-import org.schabi.newpipe.database.history.dao.SearchHistoryDAO;
-import org.schabi.newpipe.database.history.dao.StreamHistoryDAO;
-import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
-import org.schabi.newpipe.database.history.model.StreamHistoryEntity;
-import org.schabi.newpipe.database.playlist.dao.PlaylistDAO;
-import org.schabi.newpipe.database.playlist.dao.PlaylistRemoteDAO;
-import org.schabi.newpipe.database.playlist.dao.PlaylistStreamDAO;
-import org.schabi.newpipe.database.playlist.model.PlaylistEntity;
-import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
-import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
-import org.schabi.newpipe.database.stream.dao.StreamDAO;
-import org.schabi.newpipe.database.stream.dao.StreamStateDAO;
-import org.schabi.newpipe.database.stream.model.StreamEntity;
-import org.schabi.newpipe.database.stream.model.StreamStateEntity;
-import org.schabi.newpipe.database.subscription.SubscriptionDAO;
-import org.schabi.newpipe.database.subscription.SubscriptionEntity;
-
-@TypeConverters({Converters.class})
-@Database(
- entities = {
- SubscriptionEntity.class, SearchHistoryEntry.class,
- StreamEntity.class, StreamHistoryEntity.class, StreamStateEntity.class,
- PlaylistEntity.class, PlaylistStreamEntity.class, PlaylistRemoteEntity.class,
- FeedEntity.class, FeedGroupEntity.class, FeedGroupSubscriptionEntity.class,
- FeedLastUpdatedEntity.class
- },
- version = DB_VER_9
-)
-public abstract class AppDatabase extends RoomDatabase {
- public static final String DATABASE_NAME = "newpipe.db";
-
- public abstract SearchHistoryDAO searchHistoryDAO();
-
- public abstract StreamDAO streamDAO();
-
- public abstract StreamHistoryDAO streamHistoryDAO();
-
- public abstract StreamStateDAO streamStateDAO();
-
- public abstract PlaylistDAO playlistDAO();
-
- public abstract PlaylistStreamDAO playlistStreamDAO();
-
- public abstract PlaylistRemoteDAO playlistRemoteDAO();
-
- public abstract FeedDAO feedDAO();
-
- public abstract FeedGroupDAO feedGroupDAO();
-
- public abstract SubscriptionDAO subscriptionDAO();
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/AppDatabase.kt b/app/src/main/java/org/schabi/newpipe/database/AppDatabase.kt
new file mode 100644
index 000000000..286eddf7b
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/AppDatabase.kt
@@ -0,0 +1,68 @@
+/*
+ * SPDX-FileCopyrightText: 2017-2024 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database
+
+import androidx.room.Database
+import androidx.room.RoomDatabase
+import androidx.room.TypeConverters
+import org.schabi.newpipe.database.feed.dao.FeedDAO
+import org.schabi.newpipe.database.feed.dao.FeedGroupDAO
+import org.schabi.newpipe.database.feed.model.FeedEntity
+import org.schabi.newpipe.database.feed.model.FeedGroupEntity
+import org.schabi.newpipe.database.feed.model.FeedGroupSubscriptionEntity
+import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity
+import org.schabi.newpipe.database.history.dao.SearchHistoryDAO
+import org.schabi.newpipe.database.history.dao.StreamHistoryDAO
+import org.schabi.newpipe.database.history.model.SearchHistoryEntry
+import org.schabi.newpipe.database.history.model.StreamHistoryEntity
+import org.schabi.newpipe.database.playlist.dao.PlaylistDAO
+import org.schabi.newpipe.database.playlist.dao.PlaylistRemoteDAO
+import org.schabi.newpipe.database.playlist.dao.PlaylistStreamDAO
+import org.schabi.newpipe.database.playlist.model.PlaylistEntity
+import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity
+import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity
+import org.schabi.newpipe.database.stream.dao.StreamDAO
+import org.schabi.newpipe.database.stream.dao.StreamStateDAO
+import org.schabi.newpipe.database.stream.model.StreamEntity
+import org.schabi.newpipe.database.stream.model.StreamStateEntity
+import org.schabi.newpipe.database.subscription.SubscriptionDAO
+import org.schabi.newpipe.database.subscription.SubscriptionEntity
+
+@TypeConverters(Converters::class)
+@Database(
+ version = Migrations.DB_VER_9,
+ entities = [
+ SubscriptionEntity::class,
+ SearchHistoryEntry::class,
+ StreamEntity::class,
+ StreamHistoryEntity::class,
+ StreamStateEntity::class,
+ PlaylistEntity::class,
+ PlaylistStreamEntity::class,
+ PlaylistRemoteEntity::class,
+ FeedEntity::class,
+ FeedGroupEntity::class,
+ FeedGroupSubscriptionEntity::class,
+ FeedLastUpdatedEntity::class
+ ]
+)
+abstract class AppDatabase : RoomDatabase() {
+ abstract fun feedDAO(): FeedDAO
+ abstract fun feedGroupDAO(): FeedGroupDAO
+ abstract fun playlistDAO(): PlaylistDAO
+ abstract fun playlistRemoteDAO(): PlaylistRemoteDAO
+ abstract fun playlistStreamDAO(): PlaylistStreamDAO
+ abstract fun searchHistoryDAO(): SearchHistoryDAO
+ abstract fun streamDAO(): StreamDAO
+ abstract fun streamHistoryDAO(): StreamHistoryDAO
+ abstract fun streamStateDAO(): StreamStateDAO
+ abstract fun subscriptionDAO(): SubscriptionDAO
+
+ companion object {
+ const val DATABASE_NAME: String = "newpipe.db"
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/BasicDAO.java b/app/src/main/java/org/schabi/newpipe/database/BasicDAO.java
deleted file mode 100644
index 255f5ba8d..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/BasicDAO.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.schabi.newpipe.database;
-
-import androidx.room.Dao;
-import androidx.room.Delete;
-import androidx.room.Insert;
-import androidx.room.Update;
-
-import java.util.Collection;
-import java.util.List;
-
-import io.reactivex.rxjava3.core.Flowable;
-
-@Dao
-public interface BasicDAO {
- /* Inserts */
- @Insert
- long insert(Entity entity);
-
- @Insert
- List insertAll(Collection entities);
-
- /* Searches */
- Flowable> getAll();
-
- Flowable> listByService(int serviceId);
-
- /* Deletes */
- @Delete
- void delete(Entity entity);
-
- int deleteAll();
-
- /* Updates */
- @Update
- int update(Entity entity);
-
- @Update
- void update(Collection entities);
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/BasicDAO.kt b/app/src/main/java/org/schabi/newpipe/database/BasicDAO.kt
new file mode 100644
index 000000000..74c7cc87c
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/BasicDAO.kt
@@ -0,0 +1,42 @@
+/*
+ * SPDX-FileCopyrightText: 2017-2022 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database
+
+import androidx.room.Dao
+import androidx.room.Delete
+import androidx.room.Insert
+import androidx.room.Update
+import io.reactivex.rxjava3.core.Flowable
+
+@Dao
+interface BasicDAO {
+
+ /* Inserts */
+ @Insert
+ fun insert(entity: Entity): Long
+
+ @Insert
+ fun insertAll(entities: Collection): List
+
+ /* Searches */
+ fun getAll(): Flowable>
+
+ fun listByService(serviceId: Int): Flowable>
+
+ /* Deletes */
+ @Delete
+ fun delete(entity: Entity)
+
+ fun deleteAll(): Int
+
+ /* Updates */
+ @Update
+ fun update(entity: Entity): Int
+
+ @Update
+ fun update(entities: Collection)
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/LocalItem.java b/app/src/main/java/org/schabi/newpipe/database/LocalItem.java
deleted file mode 100644
index 54b856b06..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/LocalItem.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.schabi.newpipe.database;
-
-public interface LocalItem {
- LocalItemType getLocalItemType();
-
- enum LocalItemType {
- PLAYLIST_LOCAL_ITEM,
- PLAYLIST_REMOTE_ITEM,
-
- PLAYLIST_STREAM_ITEM,
- STATISTIC_STREAM_ITEM,
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/LocalItem.kt b/app/src/main/java/org/schabi/newpipe/database/LocalItem.kt
new file mode 100644
index 000000000..50529610b
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/LocalItem.kt
@@ -0,0 +1,19 @@
+/*
+ * SPDX-FileCopyrightText: 2018-2020 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database
+
+interface LocalItem {
+ val localItemType: LocalItemType
+
+ enum class LocalItemType {
+ PLAYLIST_LOCAL_ITEM,
+ PLAYLIST_REMOTE_ITEM,
+
+ PLAYLIST_STREAM_ITEM,
+ STATISTIC_STREAM_ITEM,
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/Migrations.java b/app/src/main/java/org/schabi/newpipe/database/Migrations.java
deleted file mode 100644
index c9f630869..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/Migrations.java
+++ /dev/null
@@ -1,307 +0,0 @@
-package org.schabi.newpipe.database;
-
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.room.migration.Migration;
-import androidx.sqlite.db.SupportSQLiteDatabase;
-
-import org.schabi.newpipe.MainActivity;
-
-public final class Migrations {
-
- /////////////////////////////////////////////////////////////////////////////
- // Test new migrations manually by importing a database from daily usage //
- // and checking if the migration works (Use the Database Inspector //
- // https://developer.android.com/studio/inspect/database). //
- // If you add a migration point it out in the pull request, so that //
- // others remember to test it themselves. //
- /////////////////////////////////////////////////////////////////////////////
-
- public static final int DB_VER_1 = 1;
- public static final int DB_VER_2 = 2;
- public static final int DB_VER_3 = 3;
- public static final int DB_VER_4 = 4;
- public static final int DB_VER_5 = 5;
- public static final int DB_VER_6 = 6;
- public static final int DB_VER_7 = 7;
- public static final int DB_VER_8 = 8;
- public static final int DB_VER_9 = 9;
-
- private static final String TAG = Migrations.class.getName();
- public static final boolean DEBUG = MainActivity.DEBUG;
-
- public static final Migration MIGRATION_1_2 = new Migration(DB_VER_1, DB_VER_2) {
- @Override
- public void migrate(@NonNull final SupportSQLiteDatabase database) {
- if (DEBUG) {
- Log.d(TAG, "Start migrating database");
- }
- /*
- * Unfortunately these queries must be hardcoded due to the possibility of
- * schema and names changing at a later date, thus invalidating the older migration
- * scripts if they are not hardcoded.
- * */
-
- // Not much we can do about this, since room doesn't create tables before migration.
- // It's either this or blasting the entire database anew.
- database.execSQL("CREATE INDEX `index_search_history_search` "
- + "ON `search_history` (`search`)");
- database.execSQL("CREATE TABLE IF NOT EXISTS `streams` "
- + "(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
- + "`service_id` INTEGER NOT NULL, `url` TEXT, `title` TEXT, "
- + "`stream_type` TEXT, `duration` INTEGER, `uploader` TEXT, "
- + "`thumbnail_url` TEXT)");
- database.execSQL("CREATE UNIQUE INDEX `index_streams_service_id_url` "
- + "ON `streams` (`service_id`, `url`)");
- database.execSQL("CREATE TABLE IF NOT EXISTS `stream_history` "
- + "(`stream_id` INTEGER NOT NULL, `access_date` INTEGER NOT NULL, "
- + "`repeat_count` INTEGER NOT NULL, PRIMARY KEY(`stream_id`, `access_date`), "
- + "FOREIGN KEY(`stream_id`) REFERENCES `streams`(`uid`) "
- + "ON UPDATE CASCADE ON DELETE CASCADE )");
- database.execSQL("CREATE INDEX `index_stream_history_stream_id` "
- + "ON `stream_history` (`stream_id`)");
- database.execSQL("CREATE TABLE IF NOT EXISTS `stream_state` "
- + "(`stream_id` INTEGER NOT NULL, `progress_time` INTEGER NOT NULL, "
- + "PRIMARY KEY(`stream_id`), FOREIGN KEY(`stream_id`) "
- + "REFERENCES `streams`(`uid`) ON UPDATE CASCADE ON DELETE CASCADE )");
- database.execSQL("CREATE TABLE IF NOT EXISTS `playlists` "
- + "(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
- + "`name` TEXT, `thumbnail_url` TEXT)");
- database.execSQL("CREATE INDEX `index_playlists_name` ON `playlists` (`name`)");
- database.execSQL("CREATE TABLE IF NOT EXISTS `playlist_stream_join` "
- + "(`playlist_id` INTEGER NOT NULL, `stream_id` INTEGER NOT NULL, "
- + "`join_index` INTEGER NOT NULL, PRIMARY KEY(`playlist_id`, `join_index`), "
- + "FOREIGN KEY(`playlist_id`) REFERENCES `playlists`(`uid`) "
- + "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, "
- + "FOREIGN KEY(`stream_id`) REFERENCES `streams`(`uid`) "
- + "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)");
- database.execSQL("CREATE UNIQUE INDEX "
- + "`index_playlist_stream_join_playlist_id_join_index` "
- + "ON `playlist_stream_join` (`playlist_id`, `join_index`)");
- database.execSQL("CREATE INDEX `index_playlist_stream_join_stream_id` "
- + "ON `playlist_stream_join` (`stream_id`)");
- database.execSQL("CREATE TABLE IF NOT EXISTS `remote_playlists` "
- + "(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
- + "`service_id` INTEGER NOT NULL, `name` TEXT, `url` TEXT, "
- + "`thumbnail_url` TEXT, `uploader` TEXT, `stream_count` INTEGER)");
- database.execSQL("CREATE INDEX `index_remote_playlists_name` "
- + "ON `remote_playlists` (`name`)");
- database.execSQL("CREATE UNIQUE INDEX `index_remote_playlists_service_id_url` "
- + "ON `remote_playlists` (`service_id`, `url`)");
-
- // Populate streams table with existing entries in watch history
- // Latest data first, thus ignoring older entries with the same indices
- database.execSQL("INSERT OR IGNORE INTO streams (service_id, url, title, "
- + "stream_type, duration, uploader, thumbnail_url) "
-
- + "SELECT service_id, url, title, 'VIDEO_STREAM', duration, "
- + "uploader, thumbnail_url "
-
- + "FROM watch_history "
- + "ORDER BY creation_date DESC");
-
- // Once the streams have PKs, join them with the normalized history table
- // and populate it with the remaining data from watch history
- database.execSQL("INSERT INTO stream_history (stream_id, access_date, repeat_count)"
- + "SELECT uid, creation_date, 1 "
- + "FROM watch_history INNER JOIN streams "
- + "ON watch_history.service_id == streams.service_id "
- + "AND watch_history.url == streams.url "
- + "ORDER BY creation_date DESC");
-
- database.execSQL("DROP TABLE IF EXISTS watch_history");
-
- if (DEBUG) {
- Log.d(TAG, "Stop migrating database");
- }
- }
- };
-
- public static final Migration MIGRATION_2_3 = new Migration(DB_VER_2, DB_VER_3) {
- @Override
- public void migrate(@NonNull final SupportSQLiteDatabase database) {
- // Add NOT NULLs and new fields
- database.execSQL("CREATE TABLE IF NOT EXISTS streams_new "
- + "(uid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
- + "service_id INTEGER NOT NULL, url TEXT NOT NULL, title TEXT NOT NULL, "
- + "stream_type TEXT NOT NULL, duration INTEGER NOT NULL, "
- + "uploader TEXT NOT NULL, thumbnail_url TEXT, view_count INTEGER, "
- + "textual_upload_date TEXT, upload_date INTEGER, "
- + "is_upload_date_approximation INTEGER)");
-
- database.execSQL("INSERT INTO streams_new (uid, service_id, url, title, stream_type, "
- + "duration, uploader, thumbnail_url, view_count, textual_upload_date, "
- + "upload_date, is_upload_date_approximation) "
-
- + "SELECT uid, service_id, url, ifnull(title, ''), "
- + "ifnull(stream_type, 'VIDEO_STREAM'), ifnull(duration, 0), "
- + "ifnull(uploader, ''), ifnull(thumbnail_url, ''), NULL, NULL, NULL, NULL "
-
- + "FROM streams WHERE url IS NOT NULL");
-
- database.execSQL("DROP TABLE streams");
- database.execSQL("ALTER TABLE streams_new RENAME TO streams");
- database.execSQL("CREATE UNIQUE INDEX index_streams_service_id_url "
- + "ON streams (service_id, url)");
-
- // Tables for feed feature
- database.execSQL("CREATE TABLE IF NOT EXISTS feed "
- + "(stream_id INTEGER NOT NULL, subscription_id INTEGER NOT NULL, "
- + "PRIMARY KEY(stream_id, subscription_id), "
- + "FOREIGN KEY(stream_id) REFERENCES streams(uid) "
- + "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, "
- + "FOREIGN KEY(subscription_id) REFERENCES subscriptions(uid) "
- + "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)");
- database.execSQL("CREATE INDEX index_feed_subscription_id ON feed (subscription_id)");
- database.execSQL("CREATE TABLE IF NOT EXISTS feed_group "
- + "(uid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, "
- + "icon_id INTEGER NOT NULL, sort_order INTEGER NOT NULL)");
- database.execSQL("CREATE INDEX index_feed_group_sort_order ON feed_group (sort_order)");
- database.execSQL("CREATE TABLE IF NOT EXISTS feed_group_subscription_join "
- + "(group_id INTEGER NOT NULL, subscription_id INTEGER NOT NULL, "
- + "PRIMARY KEY(group_id, subscription_id), "
- + "FOREIGN KEY(group_id) REFERENCES feed_group(uid) "
- + "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, "
- + "FOREIGN KEY(subscription_id) REFERENCES subscriptions(uid) "
- + "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)");
- database.execSQL("CREATE INDEX index_feed_group_subscription_join_subscription_id "
- + "ON feed_group_subscription_join (subscription_id)");
- database.execSQL("CREATE TABLE IF NOT EXISTS feed_last_updated "
- + "(subscription_id INTEGER NOT NULL, last_updated INTEGER, "
- + "PRIMARY KEY(subscription_id), "
- + "FOREIGN KEY(subscription_id) REFERENCES subscriptions(uid) "
- + "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)");
- }
- };
-
- public static final Migration MIGRATION_3_4 = new Migration(DB_VER_3, DB_VER_4) {
- @Override
- public void migrate(@NonNull final SupportSQLiteDatabase database) {
- database.execSQL(
- "ALTER TABLE streams ADD COLUMN uploader_url TEXT"
- );
- }
- };
-
- public static final Migration MIGRATION_4_5 = new Migration(DB_VER_4, DB_VER_5) {
- @Override
- public void migrate(@NonNull final SupportSQLiteDatabase database) {
- database.execSQL("ALTER TABLE `subscriptions` ADD COLUMN `notification_mode` "
- + "INTEGER NOT NULL DEFAULT 0");
- }
- };
-
- public static final Migration MIGRATION_5_6 = new Migration(DB_VER_5, DB_VER_6) {
- @Override
- public void migrate(@NonNull final SupportSQLiteDatabase database) {
- database.execSQL("ALTER TABLE `playlists` ADD COLUMN `is_thumbnail_permanent` "
- + "INTEGER NOT NULL DEFAULT 0");
- }
- };
-
- public static final Migration MIGRATION_6_7 = new Migration(DB_VER_6, DB_VER_7) {
- @Override
- public void migrate(@NonNull final SupportSQLiteDatabase database) {
- // Create a new column thumbnail_stream_id
- database.execSQL("ALTER TABLE `playlists` ADD COLUMN `thumbnail_stream_id` "
- + "INTEGER NOT NULL DEFAULT -1");
-
- // Migrate the thumbnail_url to the thumbnail_stream_id
- database.execSQL("UPDATE playlists SET thumbnail_stream_id = ("
- + " SELECT CASE WHEN COUNT(*) != 0 then stream_uid ELSE -1 END"
- + " FROM ("
- + " SELECT p.uid AS playlist_uid, s.uid AS stream_uid"
- + " FROM playlists p"
- + " LEFT JOIN playlist_stream_join ps ON p.uid = ps.playlist_id"
- + " LEFT JOIN streams s ON s.uid = ps.stream_id"
- + " WHERE s.thumbnail_url = p.thumbnail_url) AS temporary_table"
- + " WHERE playlist_uid = playlists.uid)");
-
- // Remove the thumbnail_url field in the playlist table
- database.execSQL("CREATE TABLE IF NOT EXISTS `playlists_new`"
- + "(uid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
- + "name TEXT, "
- + "is_thumbnail_permanent INTEGER NOT NULL, "
- + "thumbnail_stream_id INTEGER NOT NULL)");
-
- database.execSQL("INSERT INTO playlists_new"
- + " SELECT uid, name, is_thumbnail_permanent, thumbnail_stream_id "
- + " FROM playlists");
-
-
- database.execSQL("DROP TABLE playlists");
- database.execSQL("ALTER TABLE playlists_new RENAME TO playlists");
- database.execSQL("CREATE INDEX IF NOT EXISTS "
- + "`index_playlists_name` ON `playlists` (`name`)");
- }
- };
-
- public static final Migration MIGRATION_7_8 = new Migration(DB_VER_7, DB_VER_8) {
- @Override
- public void migrate(@NonNull final SupportSQLiteDatabase database) {
- database.execSQL("DELETE FROM search_history WHERE id NOT IN (SELECT id FROM (SELECT "
- + "MIN(id) as id FROM search_history GROUP BY trim(search), service_id ) tmp)");
- database.execSQL("UPDATE search_history SET search = trim(search)");
- }
- };
-
- public static final Migration MIGRATION_8_9 = new Migration(DB_VER_8, DB_VER_9) {
- @Override
- public void migrate(@NonNull final SupportSQLiteDatabase database) {
- try {
- database.beginTransaction();
-
- // Update playlists.
- // Create a temp table to initialize display_index.
- database.execSQL("CREATE TABLE `playlists_tmp` "
- + "(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
- + "`name` TEXT, `is_thumbnail_permanent` INTEGER NOT NULL, "
- + "`thumbnail_stream_id` INTEGER NOT NULL, "
- + "`display_index` INTEGER NOT NULL)");
- database.execSQL("INSERT INTO `playlists_tmp` "
- + "(`uid`, `name`, `is_thumbnail_permanent`, `thumbnail_stream_id`, "
- + "`display_index`) "
- + "SELECT `uid`, `name`, `is_thumbnail_permanent`, `thumbnail_stream_id`, "
- + "-1 "
- + "FROM `playlists`");
-
- // Replace the old table, note that this also removes the index on the name which
- // we don't need anymore.
- database.execSQL("DROP TABLE `playlists`");
- database.execSQL("ALTER TABLE `playlists_tmp` RENAME TO `playlists`");
-
-
- // Update remote_playlists.
- // Create a temp table to initialize display_index.
- database.execSQL("CREATE TABLE `remote_playlists_tmp` "
- + "(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
- + "`service_id` INTEGER NOT NULL, `name` TEXT, `url` TEXT, "
- + "`thumbnail_url` TEXT, `uploader` TEXT, "
- + "`display_index` INTEGER NOT NULL,"
- + "`stream_count` INTEGER)");
- database.execSQL("INSERT INTO `remote_playlists_tmp` (`uid`, `service_id`, "
- + "`name`, `url`, `thumbnail_url`, `uploader`, `display_index`, "
- + "`stream_count`)"
- + "SELECT `uid`, `service_id`, `name`, `url`, `thumbnail_url`, `uploader`, "
- + "-1, `stream_count` FROM `remote_playlists`");
-
- // Replace the old table, note that this also removes the index on the name which
- // we don't need anymore.
- database.execSQL("DROP TABLE `remote_playlists`");
- database.execSQL("ALTER TABLE `remote_playlists_tmp` RENAME TO `remote_playlists`");
-
- // Create index on the new table.
- database.execSQL("CREATE UNIQUE INDEX `index_remote_playlists_service_id_url` "
- + "ON `remote_playlists` (`service_id`, `url`)");
-
- database.setTransactionSuccessful();
- } finally {
- database.endTransaction();
- }
- }
- };
-
- private Migrations() {
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/Migrations.kt b/app/src/main/java/org/schabi/newpipe/database/Migrations.kt
new file mode 100644
index 000000000..8988708e6
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/Migrations.kt
@@ -0,0 +1,368 @@
+/*
+ * SPDX-FileCopyrightText: 2018-2024 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database
+
+import android.util.Log
+import androidx.room.migration.Migration
+import androidx.sqlite.db.SupportSQLiteDatabase
+import org.schabi.newpipe.MainActivity
+
+object Migrations {
+
+ // /////////////////////////////////////////////////////////////////////// //
+ // Test new migrations manually by importing a database from daily usage //
+ // and checking if the migration works (Use the Database Inspector //
+ // https://developer.android.com/studio/inspect/database). //
+ // If you add a migration point it out in the pull request, so that //
+ // others remember to test it themselves. //
+ // /////////////////////////////////////////////////////////////////////// //
+
+ const val DB_VER_1 = 1
+ const val DB_VER_2 = 2
+ const val DB_VER_3 = 3
+ const val DB_VER_4 = 4
+ const val DB_VER_5 = 5
+ const val DB_VER_6 = 6
+ const val DB_VER_7 = 7
+ const val DB_VER_8 = 8
+ const val DB_VER_9 = 9
+
+ private val TAG = Migrations::class.java.getName()
+ private val isDebug = MainActivity.DEBUG
+
+ val MIGRATION_1_2 = object : Migration(DB_VER_1, DB_VER_2) {
+ override fun migrate(db: SupportSQLiteDatabase) {
+ if (isDebug) {
+ Log.d(TAG, "Start migrating database")
+ }
+
+ /*
+ * Unfortunately these queries must be hardcoded due to the possibility of
+ * schema and names changing at a later date, thus invalidating the older migration
+ * scripts if they are not hardcoded.
+ * */
+
+ // Not much we can do about this, since room doesn't create tables before migration.
+ // It's either this or blasting the entire database anew.
+ db.execSQL(
+ "CREATE INDEX `index_search_history_search` " +
+ "ON `search_history` (`search`)"
+ )
+ db.execSQL(
+ "CREATE TABLE IF NOT EXISTS `streams` " +
+ "(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
+ "`service_id` INTEGER NOT NULL, `url` TEXT, `title` TEXT, " +
+ "`stream_type` TEXT, `duration` INTEGER, `uploader` TEXT, " +
+ "`thumbnail_url` TEXT)"
+ )
+ db.execSQL(
+ "CREATE UNIQUE INDEX `index_streams_service_id_url` " +
+ "ON `streams` (`service_id`, `url`)"
+ )
+ db.execSQL(
+ "CREATE TABLE IF NOT EXISTS `stream_history` " +
+ "(`stream_id` INTEGER NOT NULL, `access_date` INTEGER NOT NULL, " +
+ "`repeat_count` INTEGER NOT NULL, PRIMARY KEY(`stream_id`, `access_date`), " +
+ "FOREIGN KEY(`stream_id`) REFERENCES `streams`(`uid`) " +
+ "ON UPDATE CASCADE ON DELETE CASCADE )"
+ )
+ db.execSQL(
+ "CREATE INDEX `index_stream_history_stream_id` " +
+ "ON `stream_history` (`stream_id`)"
+ )
+ db.execSQL(
+ "CREATE TABLE IF NOT EXISTS `stream_state` " +
+ "(`stream_id` INTEGER NOT NULL, `progress_time` INTEGER NOT NULL, " +
+ "PRIMARY KEY(`stream_id`), FOREIGN KEY(`stream_id`) " +
+ "REFERENCES `streams`(`uid`) ON UPDATE CASCADE ON DELETE CASCADE )"
+ )
+ db.execSQL(
+ "CREATE TABLE IF NOT EXISTS `playlists` " +
+ "(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
+ "`name` TEXT, `thumbnail_url` TEXT)"
+ )
+ db.execSQL("CREATE INDEX `index_playlists_name` ON `playlists` (`name`)")
+ db.execSQL(
+ "CREATE TABLE IF NOT EXISTS `playlist_stream_join` " +
+ "(`playlist_id` INTEGER NOT NULL, `stream_id` INTEGER NOT NULL, " +
+ "`join_index` INTEGER NOT NULL, PRIMARY KEY(`playlist_id`, `join_index`), " +
+ "FOREIGN KEY(`playlist_id`) REFERENCES `playlists`(`uid`) " +
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, " +
+ "FOREIGN KEY(`stream_id`) REFERENCES `streams`(`uid`) " +
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)"
+ )
+ db.execSQL(
+ "CREATE UNIQUE INDEX " +
+ "`index_playlist_stream_join_playlist_id_join_index` " +
+ "ON `playlist_stream_join` (`playlist_id`, `join_index`)"
+ )
+ db.execSQL(
+ "CREATE INDEX `index_playlist_stream_join_stream_id` " +
+ "ON `playlist_stream_join` (`stream_id`)"
+ )
+ db.execSQL(
+ "CREATE TABLE IF NOT EXISTS `remote_playlists` " +
+ "(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
+ "`service_id` INTEGER NOT NULL, `name` TEXT, `url` TEXT, " +
+ "`thumbnail_url` TEXT, `uploader` TEXT, `stream_count` INTEGER)"
+ )
+ db.execSQL(
+ "CREATE INDEX `index_remote_playlists_name` " +
+ "ON `remote_playlists` (`name`)"
+ )
+ db.execSQL(
+ "CREATE UNIQUE INDEX `index_remote_playlists_service_id_url` " +
+ "ON `remote_playlists` (`service_id`, `url`)"
+ )
+
+ // Populate streams table with existing entries in watch history
+ // Latest data first, thus ignoring older entries with the same indices
+ db.execSQL(
+ "INSERT OR IGNORE INTO streams (service_id, url, title, " +
+ "stream_type, duration, uploader, thumbnail_url) " +
+
+ "SELECT service_id, url, title, 'VIDEO_STREAM', duration, " +
+ "uploader, thumbnail_url " +
+
+ "FROM watch_history " +
+ "ORDER BY creation_date DESC"
+ )
+
+ // Once the streams have PKs, join them with the normalized history table
+ // and populate it with the remaining data from watch history
+ db.execSQL(
+ "INSERT INTO stream_history (stream_id, access_date, repeat_count)" +
+ "SELECT uid, creation_date, 1 " +
+ "FROM watch_history INNER JOIN streams " +
+ "ON watch_history.service_id == streams.service_id " +
+ "AND watch_history.url == streams.url " +
+ "ORDER BY creation_date DESC"
+ )
+
+ db.execSQL("DROP TABLE IF EXISTS watch_history")
+
+ if (isDebug) {
+ Log.d(TAG, "Stop migrating database")
+ }
+ }
+ }
+
+ val MIGRATION_2_3 = object : Migration(DB_VER_2, DB_VER_3) {
+ override fun migrate(db: SupportSQLiteDatabase) {
+ // Add NOT NULLs and new fields
+ db.execSQL(
+ "CREATE TABLE IF NOT EXISTS streams_new " +
+ "(uid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
+ "service_id INTEGER NOT NULL, url TEXT NOT NULL, title TEXT NOT NULL, " +
+ "stream_type TEXT NOT NULL, duration INTEGER NOT NULL, " +
+ "uploader TEXT NOT NULL, thumbnail_url TEXT, view_count INTEGER, " +
+ "textual_upload_date TEXT, upload_date INTEGER, " +
+ "is_upload_date_approximation INTEGER)"
+ )
+
+ db.execSQL(
+ "INSERT INTO streams_new (uid, service_id, url, title, stream_type, " +
+ "duration, uploader, thumbnail_url, view_count, textual_upload_date, " +
+ "upload_date, is_upload_date_approximation) " +
+
+ "SELECT uid, service_id, url, ifnull(title, ''), " +
+ "ifnull(stream_type, 'VIDEO_STREAM'), ifnull(duration, 0), " +
+ "ifnull(uploader, ''), ifnull(thumbnail_url, ''), NULL, NULL, NULL, NULL " +
+
+ "FROM streams WHERE url IS NOT NULL"
+ )
+
+ db.execSQL("DROP TABLE streams")
+ db.execSQL("ALTER TABLE streams_new RENAME TO streams")
+ db.execSQL(
+ "CREATE UNIQUE INDEX index_streams_service_id_url " +
+ "ON streams (service_id, url)"
+ )
+
+ // Tables for feed feature
+ db.execSQL(
+ "CREATE TABLE IF NOT EXISTS feed " +
+ "(stream_id INTEGER NOT NULL, subscription_id INTEGER NOT NULL, " +
+ "PRIMARY KEY(stream_id, subscription_id), " +
+ "FOREIGN KEY(stream_id) REFERENCES streams(uid) " +
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, " +
+ "FOREIGN KEY(subscription_id) REFERENCES subscriptions(uid) " +
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)"
+ )
+ db.execSQL("CREATE INDEX index_feed_subscription_id ON feed (subscription_id)")
+ db.execSQL(
+ "CREATE TABLE IF NOT EXISTS feed_group " +
+ "(uid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, " +
+ "icon_id INTEGER NOT NULL, sort_order INTEGER NOT NULL)"
+ )
+ db.execSQL("CREATE INDEX index_feed_group_sort_order ON feed_group (sort_order)")
+ db.execSQL(
+ "CREATE TABLE IF NOT EXISTS feed_group_subscription_join " +
+ "(group_id INTEGER NOT NULL, subscription_id INTEGER NOT NULL, " +
+ "PRIMARY KEY(group_id, subscription_id), " +
+ "FOREIGN KEY(group_id) REFERENCES feed_group(uid) " +
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, " +
+ "FOREIGN KEY(subscription_id) REFERENCES subscriptions(uid) " +
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)"
+ )
+ db.execSQL(
+ "CREATE INDEX index_feed_group_subscription_join_subscription_id " +
+ "ON feed_group_subscription_join (subscription_id)"
+ )
+ db.execSQL(
+ "CREATE TABLE IF NOT EXISTS feed_last_updated " +
+ "(subscription_id INTEGER NOT NULL, last_updated INTEGER, " +
+ "PRIMARY KEY(subscription_id), " +
+ "FOREIGN KEY(subscription_id) REFERENCES subscriptions(uid) " +
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)"
+ )
+ }
+ }
+
+ val MIGRATION_3_4 = object : Migration(DB_VER_3, DB_VER_4) {
+ override fun migrate(db: SupportSQLiteDatabase) {
+ db.execSQL("ALTER TABLE streams ADD COLUMN uploader_url TEXT")
+ }
+ }
+
+ val MIGRATION_4_5 = object : Migration(DB_VER_4, DB_VER_5) {
+ override fun migrate(db: SupportSQLiteDatabase) {
+ db.execSQL(
+ "ALTER TABLE `subscriptions` ADD COLUMN `notification_mode` " +
+ "INTEGER NOT NULL DEFAULT 0"
+ )
+ }
+ }
+
+ val MIGRATION_5_6 = object : Migration(DB_VER_5, DB_VER_6) {
+ override fun migrate(db: SupportSQLiteDatabase) {
+ db.execSQL(
+ "ALTER TABLE `playlists` ADD COLUMN `is_thumbnail_permanent` " +
+ "INTEGER NOT NULL DEFAULT 0"
+ )
+ }
+ }
+
+ val MIGRATION_6_7 = object : Migration(DB_VER_6, DB_VER_7) {
+ override fun migrate(db: SupportSQLiteDatabase) {
+ // Create a new column thumbnail_stream_id
+ db.execSQL(
+ "ALTER TABLE `playlists` ADD COLUMN `thumbnail_stream_id` " +
+ "INTEGER NOT NULL DEFAULT -1"
+ )
+
+ // Migrate the thumbnail_url to the thumbnail_stream_id
+ db.execSQL(
+ "UPDATE playlists SET thumbnail_stream_id = (" +
+ " SELECT CASE WHEN COUNT(*) != 0 then stream_uid ELSE -1 END" +
+ " FROM (" +
+ " SELECT p.uid AS playlist_uid, s.uid AS stream_uid" +
+ " FROM playlists p" +
+ " LEFT JOIN playlist_stream_join ps ON p.uid = ps.playlist_id" +
+ " LEFT JOIN streams s ON s.uid = ps.stream_id" +
+ " WHERE s.thumbnail_url = p.thumbnail_url) AS temporary_table" +
+ " WHERE playlist_uid = playlists.uid)"
+ )
+
+ // Remove the thumbnail_url field in the playlist table
+ db.execSQL(
+ "CREATE TABLE IF NOT EXISTS `playlists_new`" +
+ "(uid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
+ "name TEXT, " +
+ "is_thumbnail_permanent INTEGER NOT NULL, " +
+ "thumbnail_stream_id INTEGER NOT NULL)"
+ )
+
+ db.execSQL(
+ "INSERT INTO playlists_new" +
+ " SELECT uid, name, is_thumbnail_permanent, thumbnail_stream_id " +
+ " FROM playlists"
+ )
+
+ db.execSQL("DROP TABLE playlists")
+ db.execSQL("ALTER TABLE playlists_new RENAME TO playlists")
+ db.execSQL(
+ "CREATE INDEX IF NOT EXISTS " +
+ "`index_playlists_name` ON `playlists` (`name`)"
+ )
+ }
+ }
+
+ val MIGRATION_7_8 = object : Migration(DB_VER_7, DB_VER_8) {
+ override fun migrate(db: SupportSQLiteDatabase) {
+ db.execSQL(
+ "DELETE FROM search_history WHERE id NOT IN (SELECT id FROM (SELECT " +
+ "MIN(id) as id FROM search_history GROUP BY trim(search), service_id ) tmp)"
+ )
+ db.execSQL("UPDATE search_history SET search = trim(search)")
+ }
+ }
+
+ val MIGRATION_8_9 = object : Migration(DB_VER_8, DB_VER_9) {
+ override fun migrate(db: SupportSQLiteDatabase) {
+ try {
+ db.beginTransaction()
+
+ // Update playlists.
+ // Create a temp table to initialize display_index.
+ db.execSQL(
+ "CREATE TABLE `playlists_tmp` " +
+ "(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
+ "`name` TEXT, `is_thumbnail_permanent` INTEGER NOT NULL, " +
+ "`thumbnail_stream_id` INTEGER NOT NULL, " +
+ "`display_index` INTEGER NOT NULL)"
+ )
+ db.execSQL(
+ "INSERT INTO `playlists_tmp` " +
+ "(`uid`, `name`, `is_thumbnail_permanent`, `thumbnail_stream_id`, " +
+ "`display_index`) " +
+ "SELECT `uid`, `name`, `is_thumbnail_permanent`, `thumbnail_stream_id`, " +
+ "-1 " +
+ "FROM `playlists`"
+ )
+
+ // Replace the old table, note that this also removes the index on the name which
+ // we don't need anymore.
+ db.execSQL("DROP TABLE `playlists`")
+ db.execSQL("ALTER TABLE `playlists_tmp` RENAME TO `playlists`")
+
+ // Update remote_playlists.
+ // Create a temp table to initialize display_index.
+ db.execSQL(
+ "CREATE TABLE `remote_playlists_tmp` " +
+ "(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
+ "`service_id` INTEGER NOT NULL, `name` TEXT, `url` TEXT, " +
+ "`thumbnail_url` TEXT, `uploader` TEXT, " +
+ "`display_index` INTEGER NOT NULL," +
+ "`stream_count` INTEGER)"
+ )
+ db.execSQL(
+ "INSERT INTO `remote_playlists_tmp` (`uid`, `service_id`, " +
+ "`name`, `url`, `thumbnail_url`, `uploader`, `display_index`, " +
+ "`stream_count`)" +
+ "SELECT `uid`, `service_id`, `name`, `url`, `thumbnail_url`, `uploader`, " +
+ "-1, `stream_count` FROM `remote_playlists`"
+ )
+
+ // Replace the old table, note that this also removes the index on the name which
+ // we don't need anymore.
+ db.execSQL("DROP TABLE `remote_playlists`")
+ db.execSQL("ALTER TABLE `remote_playlists_tmp` RENAME TO `remote_playlists`")
+
+ // Create index on the new table.
+ db.execSQL(
+ "CREATE UNIQUE INDEX `index_remote_playlists_service_id_url` " +
+ "ON `remote_playlists` (`service_id`, `url`)"
+ )
+
+ db.setTransactionSuccessful()
+ } finally {
+ db.endTransaction()
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt b/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt
index e7ed93497..d756df8b1 100644
--- a/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt
+++ b/app/src/main/java/org/schabi/newpipe/database/feed/dao/FeedDAO.kt
@@ -168,10 +168,10 @@ abstract class FeedDAO {
ON fgs.subscription_id = lu.subscription_id AND fgs.group_id = :groupId
"""
)
- abstract fun oldestSubscriptionUpdate(groupId: Long): Flowable>
+ abstract fun oldestSubscriptionUpdate(groupId: Long): Flowable>
@Query("SELECT MIN(last_updated) FROM feed_last_updated")
- abstract fun oldestSubscriptionUpdateFromAll(): Flowable>
+ abstract fun oldestSubscriptionUpdateFromAll(): Flowable>
@Query("SELECT COUNT(*) FROM feed_last_updated WHERE last_updated IS NULL")
abstract fun notLoadedCount(): Flowable
diff --git a/app/src/main/java/org/schabi/newpipe/database/history/dao/HistoryDAO.java b/app/src/main/java/org/schabi/newpipe/database/history/dao/HistoryDAO.java
deleted file mode 100644
index 1ade08122..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/history/dao/HistoryDAO.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.schabi.newpipe.database.history.dao;
-
-import org.schabi.newpipe.database.BasicDAO;
-
-public interface HistoryDAO extends BasicDAO {
- T getLatestEntry();
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/history/dao/SearchHistoryDAO.java b/app/src/main/java/org/schabi/newpipe/database/history/dao/SearchHistoryDAO.java
deleted file mode 100644
index 8a281bdb4..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/history/dao/SearchHistoryDAO.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package org.schabi.newpipe.database.history.dao;
-
-import androidx.annotation.Nullable;
-import androidx.room.Dao;
-import androidx.room.Query;
-
-import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
-
-import java.util.List;
-
-import io.reactivex.rxjava3.core.Flowable;
-
-import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.CREATION_DATE;
-import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.ID;
-import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.SEARCH;
-import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.SERVICE_ID;
-import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.TABLE_NAME;
-
-@Dao
-public interface SearchHistoryDAO extends HistoryDAO {
- String ORDER_BY_CREATION_DATE = " ORDER BY " + CREATION_DATE + " DESC";
- String ORDER_BY_MAX_CREATION_DATE = " ORDER BY MAX(" + CREATION_DATE + ") DESC";
-
- @Query("SELECT * FROM " + TABLE_NAME
- + " WHERE " + ID + " = (SELECT MAX(" + ID + ") FROM " + TABLE_NAME + ")")
- @Nullable
- SearchHistoryEntry getLatestEntry();
-
- @Query("DELETE FROM " + TABLE_NAME)
- @Override
- int deleteAll();
-
- @Query("DELETE FROM " + TABLE_NAME + " WHERE " + SEARCH + " = :query")
- int deleteAllWhereQuery(String query);
-
- @Query("SELECT * FROM " + TABLE_NAME + ORDER_BY_CREATION_DATE)
- @Override
- Flowable> getAll();
-
- @Query("SELECT " + SEARCH + " FROM " + TABLE_NAME + " GROUP BY " + SEARCH
- + ORDER_BY_MAX_CREATION_DATE + " LIMIT :limit")
- Flowable> getUniqueEntries(int limit);
-
- @Query("SELECT * FROM " + TABLE_NAME
- + " WHERE " + SERVICE_ID + " = :serviceId" + ORDER_BY_CREATION_DATE)
- @Override
- Flowable> listByService(int serviceId);
-
- @Query("SELECT " + SEARCH + " FROM " + TABLE_NAME + " WHERE " + SEARCH + " LIKE :query || '%'"
- + " GROUP BY " + SEARCH + ORDER_BY_MAX_CREATION_DATE + " LIMIT :limit")
- Flowable> getSimilarEntries(String query, int limit);
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/history/dao/SearchHistoryDAO.kt b/app/src/main/java/org/schabi/newpipe/database/history/dao/SearchHistoryDAO.kt
new file mode 100644
index 000000000..ddcb00489
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/history/dao/SearchHistoryDAO.kt
@@ -0,0 +1,43 @@
+/*
+ * SPDX-FileCopyrightText: 2017-2021 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.history.dao
+
+import androidx.room.Dao
+import androidx.room.Query
+import io.reactivex.rxjava3.core.Flowable
+import org.schabi.newpipe.database.BasicDAO
+import org.schabi.newpipe.database.history.model.SearchHistoryEntry
+
+@Dao
+interface SearchHistoryDAO : BasicDAO {
+
+ @get:Query("SELECT * FROM search_history WHERE id = (SELECT MAX(id) FROM search_history)")
+ val latestEntry: SearchHistoryEntry?
+
+ @Query("DELETE FROM search_history")
+ override fun deleteAll(): Int
+
+ @Query("DELETE FROM search_history WHERE search = :query")
+ fun deleteAllWhereQuery(query: String): Int
+
+ @Query("SELECT * FROM search_history ORDER BY creation_date DESC")
+ override fun getAll(): Flowable>
+
+ @Query("SELECT search FROM search_history GROUP BY search ORDER BY MAX(creation_date) DESC LIMIT :limit")
+ fun getUniqueEntries(limit: Int): Flowable>
+
+ @Query("SELECT * FROM search_history WHERE service_id = :serviceId ORDER BY creation_date DESC")
+ override fun listByService(serviceId: Int): Flowable>
+
+ @Query(
+ """
+ SELECT search FROM search_history WHERE search LIKE :query ||
+ '%' GROUP BY search ORDER BY MAX(creation_date) DESC LIMIT :limit
+ """
+ )
+ fun getSimilarEntries(query: String, limit: Int): Flowable>
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/history/dao/StreamHistoryDAO.java b/app/src/main/java/org/schabi/newpipe/database/history/dao/StreamHistoryDAO.java
deleted file mode 100644
index 150d4a8e5..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/history/dao/StreamHistoryDAO.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package org.schabi.newpipe.database.history.dao;
-
-import androidx.annotation.Nullable;
-import androidx.room.Dao;
-import androidx.room.Query;
-import androidx.room.RewriteQueriesToDropUnusedColumns;
-
-import org.schabi.newpipe.database.history.model.StreamHistoryEntity;
-import org.schabi.newpipe.database.history.model.StreamHistoryEntry;
-import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
-
-import java.util.List;
-
-import io.reactivex.rxjava3.core.Flowable;
-
-import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.JOIN_STREAM_ID;
-import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_ACCESS_DATE;
-import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_HISTORY_TABLE;
-import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_REPEAT_COUNT;
-import static org.schabi.newpipe.database.stream.StreamStatisticsEntry.STREAM_LATEST_DATE;
-import static org.schabi.newpipe.database.stream.StreamStatisticsEntry.STREAM_WATCH_COUNT;
-import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_ID;
-import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_TABLE;
-import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID_ALIAS;
-import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_PROGRESS_MILLIS;
-import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
-
-@Dao
-public abstract class StreamHistoryDAO implements HistoryDAO {
- @Query("SELECT * FROM " + STREAM_HISTORY_TABLE
- + " WHERE " + STREAM_ACCESS_DATE + " = "
- + "(SELECT MAX(" + STREAM_ACCESS_DATE + ") FROM " + STREAM_HISTORY_TABLE + ")")
- @Override
- @Nullable
- public abstract StreamHistoryEntity getLatestEntry();
-
- @Override
- @Query("SELECT * FROM " + STREAM_HISTORY_TABLE)
- public abstract Flowable> getAll();
-
- @Override
- @Query("DELETE FROM " + STREAM_HISTORY_TABLE)
- public abstract int deleteAll();
-
- @Override
- public Flowable> listByService(final int serviceId) {
- throw new UnsupportedOperationException();
- }
-
- @Query("SELECT * FROM " + STREAM_TABLE
- + " INNER JOIN " + STREAM_HISTORY_TABLE
- + " ON " + STREAM_ID + " = " + JOIN_STREAM_ID
- + " ORDER BY " + STREAM_ACCESS_DATE + " DESC")
- public abstract Flowable> getHistory();
-
-
- @Query("SELECT * FROM " + STREAM_TABLE
- + " INNER JOIN " + STREAM_HISTORY_TABLE
- + " ON " + STREAM_ID + " = " + JOIN_STREAM_ID
- + " ORDER BY " + STREAM_ID + " ASC")
- public abstract Flowable> getHistorySortedById();
-
- @Query("SELECT * FROM " + STREAM_HISTORY_TABLE + " WHERE " + JOIN_STREAM_ID
- + " = :streamId ORDER BY " + STREAM_ACCESS_DATE + " DESC LIMIT 1")
- @Nullable
- public abstract StreamHistoryEntity getLatestEntry(long streamId);
-
- @Query("DELETE FROM " + STREAM_HISTORY_TABLE + " WHERE " + JOIN_STREAM_ID + " = :streamId")
- public abstract int deleteStreamHistory(long streamId);
-
- @RewriteQueriesToDropUnusedColumns
- @Query("SELECT * FROM " + STREAM_TABLE
-
- // Select the latest entry and watch count for each stream id on history table
- + " INNER JOIN "
- + "(SELECT " + JOIN_STREAM_ID + ", "
- + " MAX(" + STREAM_ACCESS_DATE + ") AS " + STREAM_LATEST_DATE + ", "
- + " SUM(" + STREAM_REPEAT_COUNT + ") AS " + STREAM_WATCH_COUNT
- + " FROM " + STREAM_HISTORY_TABLE + " GROUP BY " + JOIN_STREAM_ID + ")"
-
- + " ON " + STREAM_ID + " = " + JOIN_STREAM_ID
-
- + " LEFT JOIN "
- + "(SELECT " + JOIN_STREAM_ID + " AS " + JOIN_STREAM_ID_ALIAS + ", "
- + STREAM_PROGRESS_MILLIS
- + " FROM " + STREAM_STATE_TABLE + " )"
- + " ON " + STREAM_ID + " = " + JOIN_STREAM_ID_ALIAS)
- public abstract Flowable> getStatistics();
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/history/dao/StreamHistoryDAO.kt b/app/src/main/java/org/schabi/newpipe/database/history/dao/StreamHistoryDAO.kt
new file mode 100644
index 000000000..916d4e5ed
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/history/dao/StreamHistoryDAO.kt
@@ -0,0 +1,61 @@
+/*
+ * SPDX-FileCopyrightText: 2018-2022 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.history.dao
+
+import androidx.room.Dao
+import androidx.room.Query
+import androidx.room.RewriteQueriesToDropUnusedColumns
+import io.reactivex.rxjava3.core.Flowable
+import org.schabi.newpipe.database.BasicDAO
+import org.schabi.newpipe.database.history.model.StreamHistoryEntity
+import org.schabi.newpipe.database.history.model.StreamHistoryEntry
+import org.schabi.newpipe.database.stream.StreamStatisticsEntry
+
+@Dao
+abstract class StreamHistoryDAO : BasicDAO {
+
+ @Query("SELECT * FROM stream_history")
+ abstract override fun getAll(): Flowable>
+
+ @Query("DELETE FROM stream_history")
+ abstract override fun deleteAll(): Int
+
+ override fun listByService(serviceId: Int): Flowable> {
+ throw UnsupportedOperationException()
+ }
+
+ @get:Query("SELECT * FROM streams INNER JOIN stream_history ON uid = stream_id ORDER BY access_date DESC")
+ abstract val history: Flowable>
+
+ @get:Query("SELECT * FROM streams INNER JOIN stream_history ON uid = stream_id ORDER BY uid ASC")
+ abstract val historySortedById: Flowable>
+
+ @Query("SELECT * FROM stream_history WHERE stream_id = :streamId ORDER BY access_date DESC LIMIT 1")
+ abstract fun getLatestEntry(streamId: Long): StreamHistoryEntity?
+
+ @Query("DELETE FROM stream_history WHERE stream_id = :streamId")
+ abstract fun deleteStreamHistory(streamId: Long): Int
+
+ // Select the latest entry and watch count for each stream id on history table
+ @RewriteQueriesToDropUnusedColumns
+ @Query(
+ """
+ SELECT * FROM streams
+
+ INNER JOIN (
+ SELECT stream_id, MAX(access_date) AS latestAccess, SUM(repeat_count) AS watchCount
+ FROM stream_history
+ GROUP BY stream_id
+ )
+ ON uid = stream_id
+
+ LEFT JOIN (SELECT stream_id AS stream_id_alias, progress_time FROM stream_state )
+ ON uid = stream_id_alias
+ """
+ )
+ abstract fun getStatistics(): Flowable>
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/history/model/SearchHistoryEntry.kt b/app/src/main/java/org/schabi/newpipe/database/history/model/SearchHistoryEntry.kt
index 8cb9a25ca..e6006a069 100644
--- a/app/src/main/java/org/schabi/newpipe/database/history/model/SearchHistoryEntry.kt
+++ b/app/src/main/java/org/schabi/newpipe/database/history/model/SearchHistoryEntry.kt
@@ -1,3 +1,9 @@
+/*
+ * SPDX-FileCopyrightText: 2022 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
package org.schabi.newpipe.database.history.model
import androidx.room.ColumnInfo
@@ -11,23 +17,24 @@ import java.time.OffsetDateTime
tableName = SearchHistoryEntry.TABLE_NAME,
indices = [Index(value = [SearchHistoryEntry.SEARCH])]
)
-data class SearchHistoryEntry(
- @field:ColumnInfo(name = CREATION_DATE) var creationDate: OffsetDateTime?,
- @field:ColumnInfo(
- name = SERVICE_ID
- ) var serviceId: Int,
- @field:ColumnInfo(name = SEARCH) var search: String?
-) {
+data class SearchHistoryEntry @JvmOverloads constructor(
+ @ColumnInfo(name = CREATION_DATE)
+ var creationDate: OffsetDateTime?,
+
+ @ColumnInfo(name = SERVICE_ID)
+ val serviceId: Int,
+
+ @ColumnInfo(name = SEARCH)
+ val search: String?,
+
@ColumnInfo(name = ID)
@PrimaryKey(autoGenerate = true)
- var id: Long = 0
+ val id: Long = 0,
+) {
@Ignore
fun hasEqualValues(otherEntry: SearchHistoryEntry): Boolean {
- return (
- serviceId == otherEntry.serviceId &&
- search == otherEntry.search
- )
+ return serviceId == otherEntry.serviceId && search == otherEntry.search
}
companion object {
diff --git a/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java b/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java
deleted file mode 100644
index a9d69afe8..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.schabi.newpipe.database.history.model;
-
-import androidx.annotation.NonNull;
-import androidx.room.ColumnInfo;
-import androidx.room.Entity;
-import androidx.room.ForeignKey;
-import androidx.room.Index;
-
-import org.schabi.newpipe.database.stream.model.StreamEntity;
-
-import java.time.OffsetDateTime;
-
-import static androidx.room.ForeignKey.CASCADE;
-import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.JOIN_STREAM_ID;
-import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_ACCESS_DATE;
-import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_HISTORY_TABLE;
-
-@Entity(tableName = STREAM_HISTORY_TABLE,
- primaryKeys = {JOIN_STREAM_ID, STREAM_ACCESS_DATE},
- // No need to index for timestamp as they will almost always be unique
- indices = {@Index(value = {JOIN_STREAM_ID})},
- foreignKeys = {
- @ForeignKey(entity = StreamEntity.class,
- parentColumns = StreamEntity.STREAM_ID,
- childColumns = JOIN_STREAM_ID,
- onDelete = CASCADE, onUpdate = CASCADE)
- })
-public class StreamHistoryEntity {
- public static final String STREAM_HISTORY_TABLE = "stream_history";
- public static final String JOIN_STREAM_ID = "stream_id";
- public static final String STREAM_ACCESS_DATE = "access_date";
- public static final String STREAM_REPEAT_COUNT = "repeat_count";
-
- @ColumnInfo(name = JOIN_STREAM_ID)
- private long streamUid;
-
- @NonNull
- @ColumnInfo(name = STREAM_ACCESS_DATE)
- private OffsetDateTime accessDate;
-
- @ColumnInfo(name = STREAM_REPEAT_COUNT)
- private long repeatCount;
-
- /**
- * @param streamUid the stream id this history item will refer to
- * @param accessDate the last time the stream was accessed
- * @param repeatCount the total number of views this stream received
- */
- public StreamHistoryEntity(final long streamUid,
- @NonNull final OffsetDateTime accessDate,
- final long repeatCount) {
- this.streamUid = streamUid;
- this.accessDate = accessDate;
- this.repeatCount = repeatCount;
- }
-
- public long getStreamUid() {
- return streamUid;
- }
-
- public void setStreamUid(final long streamUid) {
- this.streamUid = streamUid;
- }
-
- @NonNull
- public OffsetDateTime getAccessDate() {
- return accessDate;
- }
-
- public void setAccessDate(@NonNull final OffsetDateTime accessDate) {
- this.accessDate = accessDate;
- }
-
- public long getRepeatCount() {
- return repeatCount;
- }
-
- public void setRepeatCount(final long repeatCount) {
- this.repeatCount = repeatCount;
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.kt b/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.kt
new file mode 100644
index 000000000..db41e141c
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/history/model/StreamHistoryEntity.kt
@@ -0,0 +1,56 @@
+/*
+ * SPDX-FileCopyrightText: 2018-2022 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.history.model
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.ForeignKey
+import androidx.room.ForeignKey.Companion.CASCADE
+import androidx.room.Index
+import org.schabi.newpipe.database.history.model.StreamHistoryEntity.Companion.JOIN_STREAM_ID
+import org.schabi.newpipe.database.history.model.StreamHistoryEntity.Companion.STREAM_ACCESS_DATE
+import org.schabi.newpipe.database.history.model.StreamHistoryEntity.Companion.STREAM_HISTORY_TABLE
+import org.schabi.newpipe.database.stream.model.StreamEntity
+import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_ID
+import java.time.OffsetDateTime
+
+/**
+ * @param streamUid the stream id this history item will refer to
+ * @param accessDate the last time the stream was accessed
+ * @param repeatCount the total number of views this stream received
+ */
+@Entity(
+ tableName = STREAM_HISTORY_TABLE,
+ primaryKeys = [JOIN_STREAM_ID, STREAM_ACCESS_DATE],
+ indices = [Index(value = [JOIN_STREAM_ID])],
+ foreignKeys = [
+ ForeignKey(
+ entity = StreamEntity::class,
+ parentColumns = arrayOf(STREAM_ID),
+ childColumns = arrayOf(JOIN_STREAM_ID),
+ onDelete = CASCADE,
+ onUpdate = CASCADE
+ )
+ ]
+)
+data class StreamHistoryEntity(
+ @ColumnInfo(name = JOIN_STREAM_ID)
+ val streamUid: Long,
+
+ @ColumnInfo(name = STREAM_ACCESS_DATE)
+ var accessDate: OffsetDateTime,
+
+ @ColumnInfo(name = STREAM_REPEAT_COUNT)
+ var repeatCount: Long
+) {
+ companion object {
+ const val STREAM_HISTORY_TABLE: String = "stream_history"
+ const val STREAM_ACCESS_DATE: String = "access_date"
+ const val JOIN_STREAM_ID: String = "stream_id"
+ const val STREAM_REPEAT_COUNT: String = "repeat_count"
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistDuplicatesEntry.java b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistDuplicatesEntry.java
deleted file mode 100644
index 3be85e6e1..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistDuplicatesEntry.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.schabi.newpipe.database.playlist;
-
-import androidx.room.ColumnInfo;
-
-/**
- * This class adds a field to {@link PlaylistMetadataEntry} that contains an integer representing
- * how many times a specific stream is already contained inside a local playlist. Used to be able
- * to grey out playlists which already contain the current stream in the playlist append dialog.
- * @see org.schabi.newpipe.local.playlist.LocalPlaylistManager#getPlaylistDuplicates(String)
- */
-public class PlaylistDuplicatesEntry extends PlaylistMetadataEntry {
- public static final String PLAYLIST_TIMES_STREAM_IS_CONTAINED = "timesStreamIsContained";
- @ColumnInfo(name = PLAYLIST_TIMES_STREAM_IS_CONTAINED)
- public final long timesStreamIsContained;
-
- @SuppressWarnings("checkstyle:ParameterNumber")
- public PlaylistDuplicatesEntry(final long uid,
- final String name,
- final String thumbnailUrl,
- final boolean isThumbnailPermanent,
- final long thumbnailStreamId,
- final long displayIndex,
- final long streamCount,
- final long timesStreamIsContained) {
- super(uid, name, thumbnailUrl, isThumbnailPermanent, thumbnailStreamId, displayIndex,
- streamCount);
- this.timesStreamIsContained = timesStreamIsContained;
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistDuplicatesEntry.kt b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistDuplicatesEntry.kt
new file mode 100644
index 000000000..84972a89e
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistDuplicatesEntry.kt
@@ -0,0 +1,54 @@
+/*
+ * SPDX-FileCopyrightText: 2023-2024 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.playlist
+
+import androidx.room.ColumnInfo
+import org.schabi.newpipe.database.playlist.model.PlaylistEntity
+
+/**
+ * This class adds a field to [PlaylistMetadataEntry] that contains an integer representing
+ * how many times a specific stream is already contained inside a local playlist. Used to be able
+ * to grey out playlists which already contain the current stream in the playlist append dialog.
+ * @see org.schabi.newpipe.local.playlist.LocalPlaylistManager.getPlaylistDuplicates
+ */
+data class PlaylistDuplicatesEntry(
+ @ColumnInfo(name = PlaylistEntity.PLAYLIST_ID)
+ override val uid: Long,
+
+ @ColumnInfo(name = PlaylistEntity.PLAYLIST_THUMBNAIL_URL)
+ override val thumbnailUrl: String?,
+
+ @ColumnInfo(name = PlaylistEntity.PLAYLIST_THUMBNAIL_PERMANENT)
+ override val isThumbnailPermanent: Boolean?,
+
+ @ColumnInfo(name = PlaylistEntity.PLAYLIST_THUMBNAIL_STREAM_ID)
+ override val thumbnailStreamId: Long?,
+
+ @ColumnInfo(name = PlaylistEntity.PLAYLIST_DISPLAY_INDEX)
+ override var displayIndex: Long?,
+
+ @ColumnInfo(name = PLAYLIST_STREAM_COUNT)
+ override val streamCount: Long,
+
+ @ColumnInfo(name = PlaylistEntity.PLAYLIST_NAME)
+ override val orderingName: String?,
+
+ @ColumnInfo(name = PLAYLIST_TIMES_STREAM_IS_CONTAINED)
+ val timesStreamIsContained: Long
+) : PlaylistMetadataEntry(
+ uid = uid,
+ orderingName = orderingName,
+ thumbnailUrl = thumbnailUrl,
+ isThumbnailPermanent = isThumbnailPermanent,
+ thumbnailStreamId = thumbnailStreamId,
+ displayIndex = displayIndex,
+ streamCount = streamCount
+) {
+ companion object {
+ const val PLAYLIST_TIMES_STREAM_IS_CONTAINED: String = "timesStreamIsContained"
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistLocalItem.java b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistLocalItem.java
deleted file mode 100644
index 91f4622e9..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistLocalItem.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.schabi.newpipe.database.playlist;
-
-import androidx.annotation.Nullable;
-
-import org.schabi.newpipe.database.LocalItem;
-
-public interface PlaylistLocalItem extends LocalItem {
- String getOrderingName();
-
- long getDisplayIndex();
-
- long getUid();
-
- void setDisplayIndex(long displayIndex);
-
- @Nullable
- String getThumbnailUrl();
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistLocalItem.kt b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistLocalItem.kt
new file mode 100644
index 000000000..4f2f79aa0
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistLocalItem.kt
@@ -0,0 +1,16 @@
+/*
+ * SPDX-FileCopyrightText: 2018-2025 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.playlist
+
+import org.schabi.newpipe.database.LocalItem
+
+interface PlaylistLocalItem : LocalItem {
+ val orderingName: String?
+ val displayIndex: Long?
+ val uid: Long
+ val thumbnailUrl: String?
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistMetadataEntry.java b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistMetadataEntry.java
deleted file mode 100644
index 8fbadb020..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistMetadataEntry.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.schabi.newpipe.database.playlist;
-
-import androidx.room.ColumnInfo;
-
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_DISPLAY_INDEX;
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_ID;
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_NAME;
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_THUMBNAIL_PERMANENT;
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_THUMBNAIL_STREAM_ID;
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_THUMBNAIL_URL;
-
-import androidx.annotation.Nullable;
-
-public class PlaylistMetadataEntry implements PlaylistLocalItem {
- public static final String PLAYLIST_STREAM_COUNT = "streamCount";
-
- @ColumnInfo(name = PLAYLIST_ID)
- private final long uid;
- @ColumnInfo(name = PLAYLIST_NAME)
- public final String name;
- @ColumnInfo(name = PLAYLIST_THUMBNAIL_PERMANENT)
- private final boolean isThumbnailPermanent;
- @ColumnInfo(name = PLAYLIST_THUMBNAIL_STREAM_ID)
- private final long thumbnailStreamId;
- @ColumnInfo(name = PLAYLIST_THUMBNAIL_URL)
- public final String thumbnailUrl;
- @ColumnInfo(name = PLAYLIST_DISPLAY_INDEX)
- private long displayIndex;
- @ColumnInfo(name = PLAYLIST_STREAM_COUNT)
- public final long streamCount;
-
- public PlaylistMetadataEntry(final long uid, final String name, final String thumbnailUrl,
- final boolean isThumbnailPermanent, final long thumbnailStreamId,
- final long displayIndex, final long streamCount) {
- this.uid = uid;
- this.name = name;
- this.thumbnailUrl = thumbnailUrl;
- this.isThumbnailPermanent = isThumbnailPermanent;
- this.thumbnailStreamId = thumbnailStreamId;
- this.displayIndex = displayIndex;
- this.streamCount = streamCount;
- }
-
- @Override
- public LocalItemType getLocalItemType() {
- return LocalItemType.PLAYLIST_LOCAL_ITEM;
- }
-
- @Override
- public String getOrderingName() {
- return name;
- }
-
- public boolean isThumbnailPermanent() {
- return isThumbnailPermanent;
- }
-
- public long getThumbnailStreamId() {
- return thumbnailStreamId;
- }
-
- @Override
- public long getDisplayIndex() {
- return displayIndex;
- }
-
- @Override
- public long getUid() {
- return uid;
- }
-
- @Override
- public void setDisplayIndex(final long displayIndex) {
- this.displayIndex = displayIndex;
- }
-
- @Nullable
- @Override
- public String getThumbnailUrl() {
- return thumbnailUrl;
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistMetadataEntry.kt b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistMetadataEntry.kt
new file mode 100644
index 000000000..9b62c1380
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistMetadataEntry.kt
@@ -0,0 +1,42 @@
+/*
+ * SPDX-FileCopyrightText: 2018-2025 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.playlist
+
+import androidx.room.ColumnInfo
+import org.schabi.newpipe.database.LocalItem.LocalItemType
+import org.schabi.newpipe.database.playlist.model.PlaylistEntity
+
+open class PlaylistMetadataEntry(
+ @ColumnInfo(name = PlaylistEntity.PLAYLIST_ID)
+ override val uid: Long,
+
+ @ColumnInfo(name = PlaylistEntity.PLAYLIST_NAME)
+ override val orderingName: String?,
+
+ @ColumnInfo(name = PlaylistEntity.PLAYLIST_THUMBNAIL_URL)
+ override val thumbnailUrl: String?,
+
+ @ColumnInfo(name = PlaylistEntity.PLAYLIST_DISPLAY_INDEX)
+ override var displayIndex: Long?,
+
+ @ColumnInfo(name = PlaylistEntity.PLAYLIST_THUMBNAIL_PERMANENT)
+ open val isThumbnailPermanent: Boolean?,
+
+ @ColumnInfo(name = PlaylistEntity.PLAYLIST_THUMBNAIL_STREAM_ID)
+ open val thumbnailStreamId: Long?,
+
+ @ColumnInfo(name = PLAYLIST_STREAM_COUNT)
+ open val streamCount: Long
+) : PlaylistLocalItem {
+
+ override val localItemType: LocalItemType
+ get() = LocalItemType.PLAYLIST_LOCAL_ITEM
+
+ companion object {
+ const val PLAYLIST_STREAM_COUNT: String = "streamCount"
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt
index 1d74c6d31..90fdee2d3 100644
--- a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt
+++ b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt
@@ -1,3 +1,9 @@
+/*
+ * SPDX-FileCopyrightText: 2020-2023 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
package org.schabi.newpipe.database.playlist
import androidx.room.ColumnInfo
@@ -23,18 +29,21 @@ data class PlaylistStreamEntry(
val joinIndex: Int
) : LocalItem {
+ override val localItemType: LocalItem.LocalItemType
+ get() = LocalItem.LocalItemType.PLAYLIST_STREAM_ITEM
+
@Throws(IllegalArgumentException::class)
fun toStreamInfoItem(): StreamInfoItem {
- val item = StreamInfoItem(streamEntity.serviceId, streamEntity.url, streamEntity.title, streamEntity.streamType)
- item.duration = streamEntity.duration
- item.uploaderName = streamEntity.uploader
- item.uploaderUrl = streamEntity.uploaderUrl
- item.thumbnails = ImageStrategy.dbUrlToImageList(streamEntity.thumbnailUrl)
-
- return item
- }
-
- override fun getLocalItemType(): LocalItem.LocalItemType {
- return LocalItem.LocalItemType.PLAYLIST_STREAM_ITEM
+ return StreamInfoItem(
+ streamEntity.serviceId,
+ streamEntity.url,
+ streamEntity.title,
+ streamEntity.streamType
+ ).apply {
+ duration = streamEntity.duration
+ uploaderName = streamEntity.uploader
+ uploaderUrl = streamEntity.uploaderUrl
+ thumbnails = ImageStrategy.dbUrlToImageList(streamEntity.thumbnailUrl)
+ }
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistDAO.java b/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistDAO.java
deleted file mode 100644
index d8071e0af..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistDAO.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.schabi.newpipe.database.playlist.dao;
-
-import androidx.room.Dao;
-import androidx.room.Query;
-import androidx.room.Transaction;
-
-import org.schabi.newpipe.database.BasicDAO;
-import org.schabi.newpipe.database.playlist.model.PlaylistEntity;
-
-import java.util.List;
-
-import io.reactivex.rxjava3.core.Flowable;
-
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_ID;
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_TABLE;
-
-@Dao
-public interface PlaylistDAO extends BasicDAO {
- @Override
- @Query("SELECT * FROM " + PLAYLIST_TABLE)
- Flowable> getAll();
-
- @Override
- @Query("DELETE FROM " + PLAYLIST_TABLE)
- int deleteAll();
-
- @Override
- default Flowable> listByService(final int serviceId) {
- throw new UnsupportedOperationException();
- }
-
- @Query("SELECT * FROM " + PLAYLIST_TABLE + " WHERE " + PLAYLIST_ID + " = :playlistId")
- Flowable> getPlaylist(long playlistId);
-
- @Query("DELETE FROM " + PLAYLIST_TABLE + " WHERE " + PLAYLIST_ID + " = :playlistId")
- int deletePlaylist(long playlistId);
-
- @Query("SELECT COUNT(*) FROM " + PLAYLIST_TABLE)
- Flowable getCount();
-
- @Transaction
- default long upsertPlaylist(final PlaylistEntity playlist) {
- final long playlistId = playlist.getUid();
-
- if (playlistId == -1) {
- // This situation is probably impossible.
- return insert(playlist);
- } else {
- update(playlist);
- return playlistId;
- }
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistDAO.kt b/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistDAO.kt
new file mode 100644
index 000000000..9c2dd89a8
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistDAO.kt
@@ -0,0 +1,48 @@
+/*
+ * SPDX-FileCopyrightText: 2018-2022 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.playlist.dao
+
+import androidx.room.Dao
+import androidx.room.Query
+import androidx.room.Transaction
+import io.reactivex.rxjava3.core.Flowable
+import org.schabi.newpipe.database.BasicDAO
+import org.schabi.newpipe.database.playlist.model.PlaylistEntity
+
+@Dao
+interface PlaylistDAO : BasicDAO {
+
+ @Query("SELECT * FROM playlists")
+ override fun getAll(): Flowable>
+
+ @Query("DELETE FROM playlists")
+ override fun deleteAll(): Int
+
+ override fun listByService(serviceId: Int): Flowable> {
+ throw UnsupportedOperationException()
+ }
+
+ @Query("SELECT * FROM playlists WHERE uid = :playlistId")
+ fun getPlaylist(playlistId: Long): Flowable>
+
+ @Query("DELETE FROM playlists WHERE uid = :playlistId")
+ fun deletePlaylist(playlistId: Long): Int
+
+ @get:Query("SELECT COUNT(*) FROM playlists")
+ val count: Flowable
+
+ @Transaction
+ fun upsertPlaylist(playlist: PlaylistEntity): Long {
+ if (playlist.uid == -1L) {
+ // This situation is probably impossible.
+ return insert(playlist)
+ } else {
+ update(playlist)
+ return playlist.uid
+ }
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistRemoteDAO.java b/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistRemoteDAO.java
deleted file mode 100644
index ef77d5ade..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistRemoteDAO.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.schabi.newpipe.database.playlist.dao;
-
-import androidx.room.Dao;
-import androidx.room.Query;
-import androidx.room.Transaction;
-
-import org.schabi.newpipe.database.BasicDAO;
-import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
-
-import java.util.List;
-
-import io.reactivex.rxjava3.core.Flowable;
-
-import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_DISPLAY_INDEX;
-import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_ID;
-import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_SERVICE_ID;
-import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_TABLE;
-import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_URL;
-
-@Dao
-public interface PlaylistRemoteDAO extends BasicDAO {
- @Override
- @Query("SELECT * FROM " + REMOTE_PLAYLIST_TABLE)
- Flowable> getAll();
-
- @Override
- @Query("DELETE FROM " + REMOTE_PLAYLIST_TABLE)
- int deleteAll();
-
- @Override
- @Query("SELECT * FROM " + REMOTE_PLAYLIST_TABLE
- + " WHERE " + REMOTE_PLAYLIST_SERVICE_ID + " = :serviceId")
- Flowable> listByService(int serviceId);
-
- @Query("SELECT * FROM " + REMOTE_PLAYLIST_TABLE + " WHERE "
- + REMOTE_PLAYLIST_ID + " = :playlistId")
- Flowable getPlaylist(long playlistId);
-
- @Query("SELECT * FROM " + REMOTE_PLAYLIST_TABLE + " WHERE "
- + REMOTE_PLAYLIST_URL + " = :url AND " + REMOTE_PLAYLIST_SERVICE_ID + " = :serviceId")
- Flowable> getPlaylist(long serviceId, String url);
-
- @Query("SELECT * FROM " + REMOTE_PLAYLIST_TABLE
- + " ORDER BY " + REMOTE_PLAYLIST_DISPLAY_INDEX)
- Flowable> getPlaylists();
-
- @Query("SELECT " + REMOTE_PLAYLIST_ID + " FROM " + REMOTE_PLAYLIST_TABLE
- + " WHERE " + REMOTE_PLAYLIST_URL + " = :url "
- + "AND " + REMOTE_PLAYLIST_SERVICE_ID + " = :serviceId")
- Long getPlaylistIdInternal(long serviceId, String url);
-
- @Transaction
- default long upsert(final PlaylistRemoteEntity playlist) {
- final Long playlistId = getPlaylistIdInternal(playlist.getServiceId(), playlist.getUrl());
-
- if (playlistId == null) {
- return insert(playlist);
- } else {
- playlist.setUid(playlistId);
- update(playlist);
- return playlistId;
- }
- }
-
- @Query("DELETE FROM " + REMOTE_PLAYLIST_TABLE
- + " WHERE " + REMOTE_PLAYLIST_ID + " = :playlistId")
- int deletePlaylist(long playlistId);
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistRemoteDAO.kt b/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistRemoteDAO.kt
new file mode 100644
index 000000000..36a80bc91
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistRemoteDAO.kt
@@ -0,0 +1,55 @@
+/*
+ * SPDX-FileCopyrightText: 2018-2025 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.playlist.dao
+
+import androidx.room.Dao
+import androidx.room.Query
+import androidx.room.Transaction
+import io.reactivex.rxjava3.core.Flowable
+import org.schabi.newpipe.database.BasicDAO
+import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity
+
+@Dao
+interface PlaylistRemoteDAO : BasicDAO {
+
+ @Query("SELECT * FROM remote_playlists")
+ override fun getAll(): Flowable>
+
+ @Query("DELETE FROM remote_playlists")
+ override fun deleteAll(): Int
+
+ @Query("SELECT * FROM remote_playlists WHERE service_id = :serviceId")
+ override fun listByService(serviceId: Int): Flowable>
+
+ @Query("SELECT * FROM remote_playlists WHERE uid = :playlistId")
+ fun getPlaylist(playlistId: Long): Flowable
+
+ @Query("SELECT * FROM remote_playlists WHERE url = :url AND service_id = :serviceId")
+ fun getPlaylist(serviceId: Long, url: String?): Flowable>
+
+ @get:Query("SELECT * FROM remote_playlists ORDER BY display_index")
+ val playlists: Flowable>
+
+ @Query("SELECT uid FROM remote_playlists WHERE url = :url AND service_id = :serviceId")
+ fun getPlaylistIdInternal(serviceId: Long, url: String?): Long?
+
+ @Transaction
+ fun upsert(playlist: PlaylistRemoteEntity): Long {
+ val playlistId = getPlaylistIdInternal(playlist.serviceId.toLong(), playlist.url)
+
+ if (playlistId == null) {
+ return insert(playlist)
+ } else {
+ playlist.uid = playlistId
+ update(playlist)
+ return playlistId
+ }
+ }
+
+ @Query("DELETE FROM remote_playlists WHERE uid = :playlistId")
+ fun deletePlaylist(playlistId: Long): Int
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistStreamDAO.java b/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistStreamDAO.java
deleted file mode 100644
index 6b77166ea..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistStreamDAO.java
+++ /dev/null
@@ -1,159 +0,0 @@
-package org.schabi.newpipe.database.playlist.dao;
-
-import androidx.room.Dao;
-import androidx.room.Query;
-import androidx.room.RewriteQueriesToDropUnusedColumns;
-import androidx.room.Transaction;
-
-import org.schabi.newpipe.database.BasicDAO;
-import org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry;
-import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
-import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
-import org.schabi.newpipe.database.playlist.model.PlaylistEntity;
-import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
-
-import java.util.List;
-
-import io.reactivex.rxjava3.core.Flowable;
-
-import static org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry.PLAYLIST_TIMES_STREAM_IS_CONTAINED;
-import static org.schabi.newpipe.database.playlist.PlaylistMetadataEntry.PLAYLIST_STREAM_COUNT;
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_DISPLAY_INDEX;
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.DEFAULT_THUMBNAIL;
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_ID;
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_NAME;
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_TABLE;
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_THUMBNAIL_PERMANENT;
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_THUMBNAIL_STREAM_ID;
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_THUMBNAIL_URL;
-import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_INDEX;
-import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_PLAYLIST_ID;
-import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_STREAM_ID;
-import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.PLAYLIST_STREAM_JOIN_TABLE;
-import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_ID;
-import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_TABLE;
-import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_THUMBNAIL_URL;
-import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_URL;
-import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID_ALIAS;
-import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_PROGRESS_MILLIS;
-import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
-
-@Dao
-public interface PlaylistStreamDAO extends BasicDAO {
- @Override
- @Query("SELECT * FROM " + PLAYLIST_STREAM_JOIN_TABLE)
- Flowable> getAll();
-
- @Override
- @Query("DELETE FROM " + PLAYLIST_STREAM_JOIN_TABLE)
- int deleteAll();
-
- @Override
- default Flowable> listByService(final int serviceId) {
- throw new UnsupportedOperationException();
- }
-
- @Query("DELETE FROM " + PLAYLIST_STREAM_JOIN_TABLE
- + " WHERE " + JOIN_PLAYLIST_ID + " = :playlistId")
- void deleteBatch(long playlistId);
-
- @Query("SELECT COALESCE(MAX(" + JOIN_INDEX + "), -1)"
- + " FROM " + PLAYLIST_STREAM_JOIN_TABLE
- + " WHERE " + JOIN_PLAYLIST_ID + " = :playlistId")
- Flowable getMaximumIndexOf(long playlistId);
-
- @Query("SELECT CASE WHEN COUNT(*) != 0 then " + STREAM_ID
- + " ELSE " + PlaylistEntity.DEFAULT_THUMBNAIL_ID + " END"
- + " FROM " + STREAM_TABLE
- + " LEFT JOIN " + PLAYLIST_STREAM_JOIN_TABLE
- + " ON " + STREAM_ID + " = " + JOIN_STREAM_ID
- + " WHERE " + JOIN_PLAYLIST_ID + " = :playlistId "
- + " LIMIT 1"
- )
- Flowable getAutomaticThumbnailStreamId(long playlistId);
-
- @RewriteQueriesToDropUnusedColumns
- @Transaction
- @Query("SELECT * FROM " + STREAM_TABLE + " INNER JOIN "
- // get ids of streams of the given playlist
- + "(SELECT " + JOIN_STREAM_ID + "," + JOIN_INDEX
- + " FROM " + PLAYLIST_STREAM_JOIN_TABLE
- + " WHERE " + JOIN_PLAYLIST_ID + " = :playlistId)"
-
- // then merge with the stream metadata
- + " ON " + STREAM_ID + " = " + JOIN_STREAM_ID
-
- + " LEFT JOIN "
- + "(SELECT " + JOIN_STREAM_ID + " AS " + JOIN_STREAM_ID_ALIAS + ", "
- + STREAM_PROGRESS_MILLIS
- + " FROM " + STREAM_STATE_TABLE + " )"
- + " ON " + STREAM_ID + " = " + JOIN_STREAM_ID_ALIAS
-
- + " ORDER BY " + JOIN_INDEX + " ASC")
- Flowable> getOrderedStreamsOf(long playlistId);
-
- @Transaction
- @Query("SELECT " + PLAYLIST_ID + ", " + PLAYLIST_NAME + ", "
- + PLAYLIST_THUMBNAIL_PERMANENT + ", " + PLAYLIST_THUMBNAIL_STREAM_ID + ", "
- + PLAYLIST_DISPLAY_INDEX + ", "
-
- + " CASE WHEN " + PLAYLIST_THUMBNAIL_STREAM_ID + " = "
- + PlaylistEntity.DEFAULT_THUMBNAIL_ID + " THEN " + "'" + DEFAULT_THUMBNAIL + "'"
- + " ELSE (SELECT " + STREAM_THUMBNAIL_URL
- + " FROM " + STREAM_TABLE
- + " WHERE " + STREAM_TABLE + "." + STREAM_ID + " = " + PLAYLIST_THUMBNAIL_STREAM_ID
- + " ) END AS " + PLAYLIST_THUMBNAIL_URL + ", "
-
- + "COALESCE(COUNT(" + JOIN_PLAYLIST_ID + "), 0) AS " + PLAYLIST_STREAM_COUNT
- + " FROM " + PLAYLIST_TABLE
- + " LEFT JOIN " + PLAYLIST_STREAM_JOIN_TABLE
- + " ON " + PLAYLIST_TABLE + "." + PLAYLIST_ID + " = " + JOIN_PLAYLIST_ID
- + " GROUP BY " + PLAYLIST_ID
- + " ORDER BY " + PLAYLIST_DISPLAY_INDEX)
- Flowable> getPlaylistMetadata();
-
- @RewriteQueriesToDropUnusedColumns
- @Transaction
- @Query("SELECT *, MIN(" + JOIN_INDEX + ")"
- + " FROM " + STREAM_TABLE + " INNER JOIN"
- + " (SELECT " + JOIN_STREAM_ID + "," + JOIN_INDEX
- + " FROM " + PLAYLIST_STREAM_JOIN_TABLE
- + " WHERE " + JOIN_PLAYLIST_ID + " = :playlistId)"
- + " ON " + STREAM_ID + " = " + JOIN_STREAM_ID
- + " LEFT JOIN "
- + "(SELECT " + JOIN_STREAM_ID + " AS " + JOIN_STREAM_ID_ALIAS + ", "
- + STREAM_PROGRESS_MILLIS
- + " FROM " + STREAM_STATE_TABLE + " )"
- + " ON " + STREAM_ID + " = " + JOIN_STREAM_ID_ALIAS
- + " GROUP BY " + STREAM_ID
- + " ORDER BY MIN(" + JOIN_INDEX + ") ASC")
- Flowable> getStreamsWithoutDuplicates(long playlistId);
-
- @Transaction
- @Query("SELECT " + PLAYLIST_TABLE + "." + PLAYLIST_ID + ", " + PLAYLIST_NAME + ", "
- + PLAYLIST_THUMBNAIL_PERMANENT + ", " + PLAYLIST_THUMBNAIL_STREAM_ID + ", "
- + PLAYLIST_DISPLAY_INDEX + ", "
-
- + " CASE WHEN " + PLAYLIST_THUMBNAIL_STREAM_ID + " = "
- + PlaylistEntity.DEFAULT_THUMBNAIL_ID + " THEN " + "'" + DEFAULT_THUMBNAIL + "'"
- + " ELSE (SELECT " + STREAM_THUMBNAIL_URL
- + " FROM " + STREAM_TABLE
- + " WHERE " + STREAM_TABLE + "." + STREAM_ID + " = " + PLAYLIST_THUMBNAIL_STREAM_ID
- + " ) END AS " + PLAYLIST_THUMBNAIL_URL + ", "
-
- + "COALESCE(COUNT(" + JOIN_PLAYLIST_ID + "), 0) AS " + PLAYLIST_STREAM_COUNT + ", "
- + "COALESCE(SUM(" + STREAM_URL + " = :streamUrl), 0) AS "
- + PLAYLIST_TIMES_STREAM_IS_CONTAINED
-
- + " FROM " + PLAYLIST_TABLE
- + " LEFT JOIN " + PLAYLIST_STREAM_JOIN_TABLE
- + " ON " + PLAYLIST_TABLE + "." + PLAYLIST_ID + " = " + JOIN_PLAYLIST_ID
-
- + " LEFT JOIN " + STREAM_TABLE
- + " ON " + STREAM_TABLE + "." + STREAM_ID + " = " + JOIN_STREAM_ID
- + " AND :streamUrl = :streamUrl"
-
- + " GROUP BY " + JOIN_PLAYLIST_ID
- + " ORDER BY " + PLAYLIST_DISPLAY_INDEX + ", " + PLAYLIST_NAME)
- Flowable> getPlaylistDuplicatesMetadata(String streamUrl);
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistStreamDAO.kt b/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistStreamDAO.kt
new file mode 100644
index 000000000..8bf26d754
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistStreamDAO.kt
@@ -0,0 +1,126 @@
+/*
+ * SPDX-FileCopyrightText: 2018-2024 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.playlist.dao
+
+import androidx.room.Dao
+import androidx.room.Query
+import androidx.room.RewriteQueriesToDropUnusedColumns
+import androidx.room.Transaction
+import io.reactivex.rxjava3.core.Flowable
+import org.schabi.newpipe.database.BasicDAO
+import org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry
+import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry
+import org.schabi.newpipe.database.playlist.PlaylistStreamEntry
+import org.schabi.newpipe.database.playlist.model.PlaylistEntity.Companion.DEFAULT_THUMBNAIL_ID
+import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity
+
+@Dao
+interface PlaylistStreamDAO : BasicDAO {
+
+ @Query("SELECT * FROM playlist_stream_join")
+ override fun getAll(): Flowable>
+
+ @Query("DELETE FROM playlist_stream_join")
+ override fun deleteAll(): Int
+
+ override fun listByService(serviceId: Int): Flowable> {
+ throw UnsupportedOperationException()
+ }
+
+ @Query("DELETE FROM playlist_stream_join WHERE playlist_id = :playlistId")
+ fun deleteBatch(playlistId: Long)
+
+ @Query("SELECT COALESCE(MAX(join_index), -1) FROM playlist_stream_join WHERE playlist_id = :playlistId")
+ fun getMaximumIndexOf(playlistId: Long): Flowable
+
+ @Query(
+ """
+ SELECT CASE WHEN COUNT(*) != 0 then stream_id ELSE $DEFAULT_THUMBNAIL_ID END
+ FROM streams
+
+ LEFT JOIN playlist_stream_join
+ ON uid = stream_id
+
+ WHERE playlist_id = :playlistId LIMIT 1
+ """
+ )
+ fun getAutomaticThumbnailStreamId(playlistId: Long): Flowable
+
+ // get ids of streams of the given playlist then merge with the stream metadata
+ @RewriteQueriesToDropUnusedColumns
+ @Transaction
+ @Query(
+ """
+ SELECT * FROM streams
+
+ INNER JOIN (SELECT stream_id, join_index FROM playlist_stream_join WHERE playlist_id = :playlistId)
+ ON uid = stream_id
+
+ LEFT JOIN (SELECT stream_id AS stream_id_alias, progress_time FROM stream_state )
+ ON uid = stream_id_alias
+
+ ORDER BY join_index ASC
+ """
+ )
+ fun getOrderedStreamsOf(playlistId: Long): Flowable>
+
+ @Transaction
+ @Query(
+ """
+ SELECT uid, name, is_thumbnail_permanent, thumbnail_stream_id, display_index,
+ (SELECT thumbnail_url FROM streams WHERE streams.uid = thumbnail_stream_id) AS thumbnail_url,
+
+ COALESCE(COUNT(playlist_id), 0) AS streamCount FROM playlists
+
+ LEFT JOIN playlist_stream_join
+ ON playlists.uid = playlist_id
+
+ GROUP BY uid
+ ORDER BY display_index
+ """
+ )
+ fun getPlaylistMetadata(): Flowable>
+
+ @RewriteQueriesToDropUnusedColumns
+ @Transaction
+ @Query(
+ """
+ SELECT *, MIN(join_index) FROM streams
+
+ INNER JOIN (SELECT stream_id, join_index FROM playlist_stream_join WHERE playlist_id = :playlistId)
+ ON uid = stream_id
+
+ LEFT JOIN (SELECT stream_id AS stream_id_alias, progress_time FROM stream_state )
+ ON uid = stream_id_alias
+
+ GROUP BY uid
+ ORDER BY MIN(join_index) ASC
+ """
+ )
+ fun getStreamsWithoutDuplicates(playlistId: Long): Flowable>
+
+ @Transaction
+ @Query(
+ """
+ SELECT playlists.uid, name, is_thumbnail_permanent, thumbnail_stream_id, display_index,
+ (SELECT thumbnail_url FROM streams WHERE streams.uid = thumbnail_stream_id) AS thumbnail_url,
+
+ COALESCE(COUNT(playlist_id), 0) AS streamCount,
+ COALESCE(SUM(url = :streamUrl), 0) AS timesStreamIsContained FROM playlists
+
+ LEFT JOIN playlist_stream_join
+ ON playlists.uid = playlist_id
+
+ LEFT JOIN streams
+ ON streams.uid = stream_id AND :streamUrl = :streamUrl
+
+ GROUP BY playlist_id
+ ORDER BY display_index, name
+ """
+ )
+ fun getPlaylistDuplicatesMetadata(streamUrl: String): Flowable>
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistEntity.java b/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistEntity.java
deleted file mode 100644
index e0c1a06b7..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistEntity.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package org.schabi.newpipe.database.playlist.model;
-
-import androidx.room.ColumnInfo;
-import androidx.room.Entity;
-import androidx.room.Ignore;
-import androidx.room.PrimaryKey;
-
-import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_TABLE;
-
-import org.schabi.newpipe.R;
-import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
-
-@Entity(tableName = PLAYLIST_TABLE)
-public class PlaylistEntity {
-
- public static final String DEFAULT_THUMBNAIL = "drawable://"
- + R.drawable.placeholder_thumbnail_playlist;
- public static final long DEFAULT_THUMBNAIL_ID = -1;
-
- public static final String PLAYLIST_TABLE = "playlists";
- public static final String PLAYLIST_ID = "uid";
- public static final String PLAYLIST_NAME = "name";
- public static final String PLAYLIST_THUMBNAIL_URL = "thumbnail_url";
- public static final String PLAYLIST_DISPLAY_INDEX = "display_index";
- public static final String PLAYLIST_THUMBNAIL_PERMANENT = "is_thumbnail_permanent";
- public static final String PLAYLIST_THUMBNAIL_STREAM_ID = "thumbnail_stream_id";
-
- @PrimaryKey(autoGenerate = true)
- @ColumnInfo(name = PLAYLIST_ID)
- private long uid = 0;
-
- @ColumnInfo(name = PLAYLIST_NAME)
- private String name;
-
- @ColumnInfo(name = PLAYLIST_THUMBNAIL_PERMANENT)
- private boolean isThumbnailPermanent;
-
- @ColumnInfo(name = PLAYLIST_THUMBNAIL_STREAM_ID)
- private long thumbnailStreamId;
-
- @ColumnInfo(name = PLAYLIST_DISPLAY_INDEX)
- private long displayIndex;
-
- public PlaylistEntity(final String name, final boolean isThumbnailPermanent,
- final long thumbnailStreamId, final long displayIndex) {
- this.name = name;
- this.isThumbnailPermanent = isThumbnailPermanent;
- this.thumbnailStreamId = thumbnailStreamId;
- this.displayIndex = displayIndex;
- }
-
- @Ignore
- public PlaylistEntity(final PlaylistMetadataEntry item) {
- this.uid = item.getUid();
- this.name = item.name;
- this.isThumbnailPermanent = item.isThumbnailPermanent();
- this.thumbnailStreamId = item.getThumbnailStreamId();
- this.displayIndex = item.getDisplayIndex();
- }
-
- public long getUid() {
- return uid;
- }
-
- public void setUid(final long uid) {
- this.uid = uid;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(final String name) {
- this.name = name;
- }
-
- public long getThumbnailStreamId() {
- return thumbnailStreamId;
- }
-
- public void setThumbnailStreamId(final long thumbnailStreamId) {
- this.thumbnailStreamId = thumbnailStreamId;
- }
-
- public boolean getIsThumbnailPermanent() {
- return isThumbnailPermanent;
- }
-
- public void setIsThumbnailPermanent(final boolean isThumbnailSet) {
- this.isThumbnailPermanent = isThumbnailSet;
- }
-
- public long getDisplayIndex() {
- return displayIndex;
- }
-
- public void setDisplayIndex(final long displayIndex) {
- this.displayIndex = displayIndex;
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistEntity.kt b/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistEntity.kt
new file mode 100644
index 000000000..4ea4eb3a7
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistEntity.kt
@@ -0,0 +1,54 @@
+/*
+ * SPDX-FileCopyrightText: 2018-2024 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.playlist.model
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.Ignore
+import androidx.room.PrimaryKey
+import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry
+
+@Entity(tableName = PlaylistEntity.Companion.PLAYLIST_TABLE)
+data class PlaylistEntity @JvmOverloads constructor(
+ @PrimaryKey(autoGenerate = true)
+ @ColumnInfo(name = PLAYLIST_ID)
+ var uid: Long = 0,
+
+ @ColumnInfo(name = PLAYLIST_NAME)
+ var name: String?,
+
+ @ColumnInfo(name = PLAYLIST_THUMBNAIL_PERMANENT)
+ var isThumbnailPermanent: Boolean,
+
+ @ColumnInfo(name = PLAYLIST_THUMBNAIL_STREAM_ID)
+ var thumbnailStreamId: Long,
+
+ @ColumnInfo(name = PLAYLIST_DISPLAY_INDEX)
+ var displayIndex: Long
+) {
+
+ @Ignore
+ constructor(item: PlaylistMetadataEntry) : this(
+ uid = item.uid,
+ name = item.orderingName,
+ isThumbnailPermanent = item.isThumbnailPermanent!!,
+ thumbnailStreamId = item.thumbnailStreamId!!,
+ displayIndex = item.displayIndex!!,
+ )
+
+ companion object {
+ const val DEFAULT_THUMBNAIL_ID = -1L
+
+ const val PLAYLIST_TABLE = "playlists"
+ const val PLAYLIST_ID = "uid"
+ const val PLAYLIST_NAME = "name"
+ const val PLAYLIST_THUMBNAIL_URL = "thumbnail_url"
+ const val PLAYLIST_DISPLAY_INDEX = "display_index"
+ const val PLAYLIST_THUMBNAIL_PERMANENT = "is_thumbnail_permanent"
+ const val PLAYLIST_THUMBNAIL_STREAM_ID = "thumbnail_stream_id"
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistRemoteEntity.java b/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistRemoteEntity.java
deleted file mode 100644
index 0b0e3605e..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistRemoteEntity.java
+++ /dev/null
@@ -1,191 +0,0 @@
-package org.schabi.newpipe.database.playlist.model;
-
-import android.text.TextUtils;
-
-import androidx.annotation.Nullable;
-import androidx.room.ColumnInfo;
-import androidx.room.Entity;
-import androidx.room.Ignore;
-import androidx.room.Index;
-import androidx.room.PrimaryKey;
-
-import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
-import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
-import org.schabi.newpipe.util.Constants;
-import org.schabi.newpipe.util.image.ImageStrategy;
-
-import static org.schabi.newpipe.database.LocalItem.LocalItemType.PLAYLIST_REMOTE_ITEM;
-import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_NAME;
-import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_SERVICE_ID;
-import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_TABLE;
-import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_URL;
-
-@Entity(tableName = REMOTE_PLAYLIST_TABLE,
- indices = {
- @Index(value = {REMOTE_PLAYLIST_SERVICE_ID, REMOTE_PLAYLIST_URL}, unique = true)
- })
-public class PlaylistRemoteEntity implements PlaylistLocalItem {
- public static final String REMOTE_PLAYLIST_TABLE = "remote_playlists";
- public static final String REMOTE_PLAYLIST_ID = "uid";
- public static final String REMOTE_PLAYLIST_SERVICE_ID = "service_id";
- public static final String REMOTE_PLAYLIST_NAME = "name";
- public static final String REMOTE_PLAYLIST_URL = "url";
- public static final String REMOTE_PLAYLIST_THUMBNAIL_URL = "thumbnail_url";
- public static final String REMOTE_PLAYLIST_UPLOADER_NAME = "uploader";
- public static final String REMOTE_PLAYLIST_DISPLAY_INDEX = "display_index";
- public static final String REMOTE_PLAYLIST_STREAM_COUNT = "stream_count";
-
- @PrimaryKey(autoGenerate = true)
- @ColumnInfo(name = REMOTE_PLAYLIST_ID)
- private long uid = 0;
-
- @ColumnInfo(name = REMOTE_PLAYLIST_SERVICE_ID)
- private int serviceId = Constants.NO_SERVICE_ID;
-
- @ColumnInfo(name = REMOTE_PLAYLIST_NAME)
- private String name;
-
- @ColumnInfo(name = REMOTE_PLAYLIST_URL)
- private String url;
-
- @ColumnInfo(name = REMOTE_PLAYLIST_THUMBNAIL_URL)
- private String thumbnailUrl;
-
- @ColumnInfo(name = REMOTE_PLAYLIST_UPLOADER_NAME)
- private String uploader;
-
- @ColumnInfo(name = REMOTE_PLAYLIST_DISPLAY_INDEX)
- private long displayIndex = -1; // Make sure the new item is on the top
-
- @ColumnInfo(name = REMOTE_PLAYLIST_STREAM_COUNT)
- private Long streamCount;
-
- public PlaylistRemoteEntity(final int serviceId, final String name, final String url,
- final String thumbnailUrl, final String uploader,
- final Long streamCount) {
- this.serviceId = serviceId;
- this.name = name;
- this.url = url;
- this.thumbnailUrl = thumbnailUrl;
- this.uploader = uploader;
- this.streamCount = streamCount;
- }
-
- @Ignore
- public PlaylistRemoteEntity(final int serviceId, final String name, final String url,
- final String thumbnailUrl, final String uploader,
- final long displayIndex, final Long streamCount) {
- this.serviceId = serviceId;
- this.name = name;
- this.url = url;
- this.thumbnailUrl = thumbnailUrl;
- this.uploader = uploader;
- this.displayIndex = displayIndex;
- this.streamCount = streamCount;
- }
-
- @Ignore
- public PlaylistRemoteEntity(final PlaylistInfo info) {
- this(info.getServiceId(), info.getName(), info.getUrl(),
- // use uploader avatar when no thumbnail is available
- ImageStrategy.imageListToDbUrl(info.getThumbnails().isEmpty()
- ? info.getUploaderAvatars() : info.getThumbnails()),
- info.getUploaderName(), info.getStreamCount());
- }
-
- @Ignore
- public boolean isIdenticalTo(final PlaylistInfo info) {
- /*
- * Returns boolean comparing the online playlist and the local copy.
- * (False if info changed such as playlist name or track count)
- */
- return getServiceId() == info.getServiceId()
- && getStreamCount() == info.getStreamCount()
- && TextUtils.equals(getName(), info.getName())
- && TextUtils.equals(getUrl(), info.getUrl())
- // we want to update the local playlist data even when either the remote thumbnail
- // URL changes, or the preferred image quality setting is changed by the user
- && TextUtils.equals(getThumbnailUrl(),
- ImageStrategy.imageListToDbUrl(info.getThumbnails()))
- && TextUtils.equals(getUploader(), info.getUploaderName());
- }
-
- @Override
- public long getUid() {
- return uid;
- }
-
- public void setUid(final long uid) {
- this.uid = uid;
- }
-
- public int getServiceId() {
- return serviceId;
- }
-
- public void setServiceId(final int serviceId) {
- this.serviceId = serviceId;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(final String name) {
- this.name = name;
- }
-
- @Nullable
- @Override
- public String getThumbnailUrl() {
- return thumbnailUrl;
- }
-
- public void setThumbnailUrl(final String thumbnailUrl) {
- this.thumbnailUrl = thumbnailUrl;
- }
-
- public String getUrl() {
- return url;
- }
-
- public void setUrl(final String url) {
- this.url = url;
- }
-
- public String getUploader() {
- return uploader;
- }
-
- public void setUploader(final String uploader) {
- this.uploader = uploader;
- }
-
- @Override
- public long getDisplayIndex() {
- return displayIndex;
- }
-
- @Override
- public void setDisplayIndex(final long displayIndex) {
- this.displayIndex = displayIndex;
- }
-
- public Long getStreamCount() {
- return streamCount;
- }
-
- public void setStreamCount(final Long streamCount) {
- this.streamCount = streamCount;
- }
-
- @Override
- public LocalItemType getLocalItemType() {
- return PLAYLIST_REMOTE_ITEM;
- }
-
- @Override
- public String getOrderingName() {
- return name;
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistRemoteEntity.kt b/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistRemoteEntity.kt
new file mode 100644
index 000000000..82162e1e4
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistRemoteEntity.kt
@@ -0,0 +1,104 @@
+/*
+ * SPDX-FileCopyrightText: 2018-2025 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.playlist.model
+
+import android.text.TextUtils
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.Ignore
+import androidx.room.Index
+import androidx.room.PrimaryKey
+import org.schabi.newpipe.database.LocalItem.LocalItemType
+import org.schabi.newpipe.database.playlist.PlaylistLocalItem
+import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.Companion.REMOTE_PLAYLIST_SERVICE_ID
+import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.Companion.REMOTE_PLAYLIST_TABLE
+import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.Companion.REMOTE_PLAYLIST_URL
+import org.schabi.newpipe.extractor.playlist.PlaylistInfo
+import org.schabi.newpipe.util.NO_SERVICE_ID
+import org.schabi.newpipe.util.image.ImageStrategy
+
+@Entity(
+ tableName = REMOTE_PLAYLIST_TABLE,
+ indices = [
+ Index(
+ value = [REMOTE_PLAYLIST_SERVICE_ID, REMOTE_PLAYLIST_URL],
+ unique = true
+ )
+ ]
+)
+data class PlaylistRemoteEntity(
+ @PrimaryKey(autoGenerate = true)
+ @ColumnInfo(name = REMOTE_PLAYLIST_ID)
+ override var uid: Long = 0,
+
+ @ColumnInfo(name = REMOTE_PLAYLIST_SERVICE_ID)
+ val serviceId: Int = NO_SERVICE_ID,
+
+ @ColumnInfo(name = REMOTE_PLAYLIST_NAME)
+ override val orderingName: String?,
+
+ @ColumnInfo(name = REMOTE_PLAYLIST_URL)
+ val url: String?,
+
+ @ColumnInfo(name = REMOTE_PLAYLIST_THUMBNAIL_URL)
+ override val thumbnailUrl: String?,
+
+ @ColumnInfo(name = REMOTE_PLAYLIST_UPLOADER_NAME)
+ val uploader: String?,
+
+ @ColumnInfo(name = REMOTE_PLAYLIST_DISPLAY_INDEX)
+ override var displayIndex: Long = -1, // Make sure the new item is on the top
+
+ @ColumnInfo(name = REMOTE_PLAYLIST_STREAM_COUNT)
+ val streamCount: Long?
+) : PlaylistLocalItem {
+
+ constructor(playlistInfo: PlaylistInfo) : this(
+ serviceId = playlistInfo.serviceId,
+ orderingName = playlistInfo.name,
+ url = playlistInfo.url,
+ thumbnailUrl = ImageStrategy.imageListToDbUrl(
+ if (playlistInfo.thumbnails.isEmpty()) {
+ playlistInfo.uploaderAvatars
+ } else {
+ playlistInfo.thumbnails
+ }
+ ),
+ uploader = playlistInfo.uploaderName,
+ streamCount = playlistInfo.streamCount
+ )
+
+ override val localItemType: LocalItemType
+ get() = LocalItemType.PLAYLIST_REMOTE_ITEM
+
+ /**
+ * Returns boolean comparing the online playlist and the local copy.
+ * (False if info changed such as playlist name or track count)
+ */
+ @Ignore
+ fun isIdenticalTo(info: PlaylistInfo): Boolean {
+ return this.serviceId == info.serviceId && this.streamCount == info.streamCount &&
+ TextUtils.equals(this.orderingName, info.name) &&
+ TextUtils.equals(this.url, info.url) &&
+ // we want to update the local playlist data even when either the remote thumbnail
+ // URL changes, or the preferred image quality setting is changed by the user
+ TextUtils.equals(thumbnailUrl, ImageStrategy.imageListToDbUrl(info.thumbnails)) &&
+ TextUtils.equals(this.uploader, info.uploaderName)
+ }
+
+ companion object {
+ const val REMOTE_PLAYLIST_TABLE = "remote_playlists"
+ const val REMOTE_PLAYLIST_ID = "uid"
+ const val REMOTE_PLAYLIST_SERVICE_ID = "service_id"
+ const val REMOTE_PLAYLIST_NAME = "name"
+ const val REMOTE_PLAYLIST_URL = "url"
+ const val REMOTE_PLAYLIST_THUMBNAIL_URL = "thumbnail_url"
+ const val REMOTE_PLAYLIST_UPLOADER_NAME = "uploader"
+ const val REMOTE_PLAYLIST_DISPLAY_INDEX = "display_index"
+ const val REMOTE_PLAYLIST_STREAM_COUNT = "stream_count"
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistStreamEntity.java b/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistStreamEntity.java
deleted file mode 100644
index f3208b6d5..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistStreamEntity.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package org.schabi.newpipe.database.playlist.model;
-
-import androidx.room.ColumnInfo;
-import androidx.room.Entity;
-import androidx.room.ForeignKey;
-import androidx.room.Index;
-
-import org.schabi.newpipe.database.stream.model.StreamEntity;
-
-import static androidx.room.ForeignKey.CASCADE;
-import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_INDEX;
-import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_PLAYLIST_ID;
-import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_STREAM_ID;
-import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.PLAYLIST_STREAM_JOIN_TABLE;
-
-@Entity(tableName = PLAYLIST_STREAM_JOIN_TABLE,
- primaryKeys = {JOIN_PLAYLIST_ID, JOIN_INDEX},
- indices = {
- @Index(value = {JOIN_PLAYLIST_ID, JOIN_INDEX}, unique = true),
- @Index(value = {JOIN_STREAM_ID})
- },
- foreignKeys = {
- @ForeignKey(entity = PlaylistEntity.class,
- parentColumns = PlaylistEntity.PLAYLIST_ID,
- childColumns = JOIN_PLAYLIST_ID,
- onDelete = CASCADE, onUpdate = CASCADE, deferred = true),
- @ForeignKey(entity = StreamEntity.class,
- parentColumns = StreamEntity.STREAM_ID,
- childColumns = JOIN_STREAM_ID,
- onDelete = CASCADE, onUpdate = CASCADE, deferred = true)
- })
-public class PlaylistStreamEntity {
- public static final String PLAYLIST_STREAM_JOIN_TABLE = "playlist_stream_join";
- public static final String JOIN_PLAYLIST_ID = "playlist_id";
- public static final String JOIN_STREAM_ID = "stream_id";
- public static final String JOIN_INDEX = "join_index";
-
- @ColumnInfo(name = JOIN_PLAYLIST_ID)
- private long playlistUid;
-
- @ColumnInfo(name = JOIN_STREAM_ID)
- private long streamUid;
-
- @ColumnInfo(name = JOIN_INDEX)
- private int index;
-
- public PlaylistStreamEntity(final long playlistUid, final long streamUid, final int index) {
- this.playlistUid = playlistUid;
- this.streamUid = streamUid;
- this.index = index;
- }
-
- public long getPlaylistUid() {
- return playlistUid;
- }
-
- public void setPlaylistUid(final long playlistUid) {
- this.playlistUid = playlistUid;
- }
-
- public long getStreamUid() {
- return streamUid;
- }
-
- public void setStreamUid(final long streamUid) {
- this.streamUid = streamUid;
- }
-
- public int getIndex() {
- return index;
- }
-
- public void setIndex(final int index) {
- this.index = index;
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistStreamEntity.kt b/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistStreamEntity.kt
new file mode 100644
index 000000000..6ab1b6ac4
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistStreamEntity.kt
@@ -0,0 +1,68 @@
+/*
+ * SPDX-FileCopyrightText: 2018-2020 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.playlist.model
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.ForeignKey
+import androidx.room.ForeignKey.Companion.CASCADE
+import androidx.room.Index
+import org.schabi.newpipe.database.LocalItem
+import org.schabi.newpipe.database.playlist.model.PlaylistEntity.Companion.PLAYLIST_ID
+import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.Companion.JOIN_INDEX
+import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.Companion.JOIN_PLAYLIST_ID
+import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.Companion.JOIN_STREAM_ID
+import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.Companion.PLAYLIST_STREAM_JOIN_TABLE
+import org.schabi.newpipe.database.stream.model.StreamEntity
+
+@Entity(
+ tableName = PLAYLIST_STREAM_JOIN_TABLE,
+ primaryKeys = [JOIN_PLAYLIST_ID, JOIN_INDEX],
+ indices = [
+ Index(value = [JOIN_PLAYLIST_ID, JOIN_INDEX], unique = true),
+ Index(value = [JOIN_STREAM_ID])
+ ],
+ foreignKeys = [
+ ForeignKey(
+ entity = PlaylistEntity::class,
+ parentColumns = arrayOf(PLAYLIST_ID),
+ childColumns = arrayOf(JOIN_PLAYLIST_ID),
+ onDelete = CASCADE,
+ onUpdate = CASCADE,
+ deferred = true
+ ),
+ ForeignKey(
+ entity = StreamEntity::class,
+ parentColumns = arrayOf(StreamEntity.STREAM_ID),
+ childColumns = arrayOf(JOIN_STREAM_ID),
+ onDelete = CASCADE,
+ onUpdate = CASCADE,
+ deferred = true
+ )
+ ]
+)
+data class PlaylistStreamEntity(
+ @ColumnInfo(name = JOIN_PLAYLIST_ID)
+ val playlistUid: Long,
+
+ @ColumnInfo(name = JOIN_STREAM_ID)
+ val streamUid: Long,
+
+ @ColumnInfo(name = JOIN_INDEX)
+ val index: Int
+) : LocalItem {
+
+ override val localItemType: LocalItem.LocalItemType
+ get() = LocalItem.LocalItemType.PLAYLIST_STREAM_ITEM
+
+ companion object {
+ const val PLAYLIST_STREAM_JOIN_TABLE = "playlist_stream_join"
+ const val JOIN_PLAYLIST_ID = "playlist_id"
+ const val JOIN_STREAM_ID = "stream_id"
+ const val JOIN_INDEX = "join_index"
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/stream/StreamStatisticsEntry.kt b/app/src/main/java/org/schabi/newpipe/database/stream/StreamStatisticsEntry.kt
index 1f3654e7a..3fa281e45 100644
--- a/app/src/main/java/org/schabi/newpipe/database/stream/StreamStatisticsEntry.kt
+++ b/app/src/main/java/org/schabi/newpipe/database/stream/StreamStatisticsEntry.kt
@@ -1,16 +1,23 @@
+/*
+ * SPDX-FileCopyrightText: 2020-2023 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
package org.schabi.newpipe.database.stream
import androidx.room.ColumnInfo
import androidx.room.Embedded
+import androidx.room.Ignore
import org.schabi.newpipe.database.LocalItem
import org.schabi.newpipe.database.history.model.StreamHistoryEntity
import org.schabi.newpipe.database.stream.model.StreamEntity
-import org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_PROGRESS_MILLIS
+import org.schabi.newpipe.database.stream.model.StreamStateEntity.Companion.STREAM_PROGRESS_MILLIS
import org.schabi.newpipe.extractor.stream.StreamInfoItem
import org.schabi.newpipe.util.image.ImageStrategy
import java.time.OffsetDateTime
-class StreamStatisticsEntry(
+data class StreamStatisticsEntry(
@Embedded
val streamEntity: StreamEntity,
@@ -26,18 +33,23 @@ class StreamStatisticsEntry(
@ColumnInfo(name = STREAM_WATCH_COUNT)
val watchCount: Long
) : LocalItem {
+
+ override val localItemType: LocalItem.LocalItemType
+ get() = LocalItem.LocalItemType.STATISTIC_STREAM_ITEM
+
+ @Ignore
fun toStreamInfoItem(): StreamInfoItem {
- val item = StreamInfoItem(streamEntity.serviceId, streamEntity.url, streamEntity.title, streamEntity.streamType)
- item.duration = streamEntity.duration
- item.uploaderName = streamEntity.uploader
- item.uploaderUrl = streamEntity.uploaderUrl
- item.thumbnails = ImageStrategy.dbUrlToImageList(streamEntity.thumbnailUrl)
-
- return item
- }
-
- override fun getLocalItemType(): LocalItem.LocalItemType {
- return LocalItem.LocalItemType.STATISTIC_STREAM_ITEM
+ return StreamInfoItem(
+ streamEntity.serviceId,
+ streamEntity.url,
+ streamEntity.title,
+ streamEntity.streamType
+ ).apply {
+ duration = streamEntity.duration
+ uploaderName = streamEntity.uploader
+ uploaderUrl = streamEntity.uploaderUrl
+ thumbnails = ImageStrategy.dbUrlToImageList(streamEntity.thumbnailUrl)
+ }
}
companion object {
diff --git a/app/src/main/java/org/schabi/newpipe/database/stream/dao/StreamStateDAO.java b/app/src/main/java/org/schabi/newpipe/database/stream/dao/StreamStateDAO.java
deleted file mode 100644
index 06371248d..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/stream/dao/StreamStateDAO.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.schabi.newpipe.database.stream.dao;
-
-import androidx.room.Dao;
-import androidx.room.Insert;
-import androidx.room.OnConflictStrategy;
-import androidx.room.Query;
-import androidx.room.Transaction;
-
-import org.schabi.newpipe.database.BasicDAO;
-import org.schabi.newpipe.database.stream.model.StreamStateEntity;
-
-import java.util.List;
-
-import io.reactivex.rxjava3.core.Flowable;
-
-import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID;
-import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
-
-@Dao
-public interface StreamStateDAO extends BasicDAO {
- @Override
- @Query("SELECT * FROM " + STREAM_STATE_TABLE)
- Flowable> getAll();
-
- @Override
- @Query("DELETE FROM " + STREAM_STATE_TABLE)
- int deleteAll();
-
- @Override
- default Flowable> listByService(final int serviceId) {
- throw new UnsupportedOperationException();
- }
-
- @Query("SELECT * FROM " + STREAM_STATE_TABLE + " WHERE " + JOIN_STREAM_ID + " = :streamId")
- Flowable> getState(long streamId);
-
- @Query("DELETE FROM " + STREAM_STATE_TABLE + " WHERE " + JOIN_STREAM_ID + " = :streamId")
- int deleteState(long streamId);
-
- @Insert(onConflict = OnConflictStrategy.IGNORE)
- void silentInsertInternal(StreamStateEntity streamState);
-
- @Transaction
- default long upsert(final StreamStateEntity stream) {
- silentInsertInternal(stream);
- return update(stream);
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/stream/dao/StreamStateDAO.kt b/app/src/main/java/org/schabi/newpipe/database/stream/dao/StreamStateDAO.kt
new file mode 100644
index 000000000..f3c44f1f2
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/stream/dao/StreamStateDAO.kt
@@ -0,0 +1,45 @@
+/*
+ * SPDX-FileCopyrightText: 2018-2021 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.stream.dao
+
+import androidx.room.Dao
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.Query
+import androidx.room.Transaction
+import io.reactivex.rxjava3.core.Flowable
+import org.schabi.newpipe.database.BasicDAO
+import org.schabi.newpipe.database.stream.model.StreamStateEntity
+
+@Dao
+interface StreamStateDAO : BasicDAO {
+
+ @Query("SELECT * FROM " + StreamStateEntity.STREAM_STATE_TABLE)
+ override fun getAll(): Flowable>
+
+ @Query("DELETE FROM " + StreamStateEntity.STREAM_STATE_TABLE)
+ override fun deleteAll(): Int
+
+ override fun listByService(serviceId: Int): Flowable> {
+ throw UnsupportedOperationException()
+ }
+
+ @Query("SELECT * FROM " + StreamStateEntity.STREAM_STATE_TABLE + " WHERE " + StreamStateEntity.JOIN_STREAM_ID + " = :streamId")
+ fun getState(streamId: Long): Flowable>
+
+ @Query("DELETE FROM " + StreamStateEntity.STREAM_STATE_TABLE + " WHERE " + StreamStateEntity.JOIN_STREAM_ID + " = :streamId")
+ fun deleteState(streamId: Long): Int
+
+ @Insert(onConflict = OnConflictStrategy.Companion.IGNORE)
+ fun silentInsertInternal(streamState: StreamStateEntity)
+
+ @Transaction
+ fun upsert(stream: StreamStateEntity): Long {
+ silentInsertInternal(stream)
+ return update(stream).toLong()
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamStateEntity.java b/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamStateEntity.java
deleted file mode 100644
index 627acea45..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamStateEntity.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package org.schabi.newpipe.database.stream.model;
-
-import androidx.annotation.Nullable;
-import androidx.room.ColumnInfo;
-import androidx.room.Entity;
-import androidx.room.ForeignKey;
-
-import java.util.Objects;
-
-import static androidx.room.ForeignKey.CASCADE;
-import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID;
-import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
-
-@Entity(tableName = STREAM_STATE_TABLE,
- primaryKeys = {JOIN_STREAM_ID},
- foreignKeys = {
- @ForeignKey(entity = StreamEntity.class,
- parentColumns = StreamEntity.STREAM_ID,
- childColumns = JOIN_STREAM_ID,
- onDelete = CASCADE, onUpdate = CASCADE)
- })
-public class StreamStateEntity {
- public static final String STREAM_STATE_TABLE = "stream_state";
- public static final String JOIN_STREAM_ID = "stream_id";
- // This additional field is required for the SQL query because 'stream_id' is used
- // for some other joins already
- public static final String JOIN_STREAM_ID_ALIAS = "stream_id_alias";
- public static final String STREAM_PROGRESS_MILLIS = "progress_time";
-
- /**
- * Playback state will not be saved, if playback time is less than this threshold (5000ms = 5s).
- */
- public static final long PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS = 5000;
-
- /**
- * Stream will be considered finished if the playback time left exceeds this threshold
- * (60000ms = 60s).
- * @see #isFinished(long)
- * @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreams()
- * @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreamsForGroup(long)
- */
- public static final long PLAYBACK_FINISHED_END_MILLISECONDS = 60000;
-
- @ColumnInfo(name = JOIN_STREAM_ID)
- private long streamUid;
-
- @ColumnInfo(name = STREAM_PROGRESS_MILLIS)
- private long progressMillis;
-
- public StreamStateEntity(final long streamUid, final long progressMillis) {
- this.streamUid = streamUid;
- this.progressMillis = progressMillis;
- }
-
- public long getStreamUid() {
- return streamUid;
- }
-
- public void setStreamUid(final long streamUid) {
- this.streamUid = streamUid;
- }
-
- public long getProgressMillis() {
- return progressMillis;
- }
-
- public void setProgressMillis(final long progressMillis) {
- this.progressMillis = progressMillis;
- }
-
- /**
- * The state will be considered valid, and thus be saved, if the progress is more than {@link
- * #PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS} or at least 1/4 of the video length.
- * @param durationInSeconds the duration of the stream connected with this state, in seconds
- * @return whether this stream state entity should be saved or not
- */
- public boolean isValid(final long durationInSeconds) {
- return progressMillis > PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS
- || progressMillis > durationInSeconds * 1000 / 4;
- }
-
- /**
- * The video will be considered as finished, if the time left is less than {@link
- * #PLAYBACK_FINISHED_END_MILLISECONDS} and the progress is at least 3/4 of the video length.
- * The state will be saved anyway, so that it can be shown under stream info items, but the
- * player will not resume if a state is considered as finished. Finished streams are also the
- * ones that can be filtered out in the feed fragment.
- * @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreams()
- * @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreamsForGroup(long)
- * @param durationInSeconds the duration of the stream connected with this state, in seconds
- * @return whether the stream is finished or not
- */
- public boolean isFinished(final long durationInSeconds) {
- return progressMillis >= durationInSeconds * 1000 - PLAYBACK_FINISHED_END_MILLISECONDS
- && progressMillis >= durationInSeconds * 1000 * 3 / 4;
- }
-
- @Override
- public boolean equals(@Nullable final Object obj) {
- if (obj instanceof StreamStateEntity) {
- return ((StreamStateEntity) obj).streamUid == streamUid
- && ((StreamStateEntity) obj).progressMillis == progressMillis;
- } else {
- return false;
- }
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(streamUid, progressMillis);
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamStateEntity.kt b/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamStateEntity.kt
new file mode 100644
index 000000000..759a2dcec
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamStateEntity.kt
@@ -0,0 +1,85 @@
+/*
+ * SPDX-FileCopyrightText: 2018-2023 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.stream.model
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.ForeignKey
+import androidx.room.ForeignKey.Companion.CASCADE
+import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_ID
+import org.schabi.newpipe.database.stream.model.StreamStateEntity.Companion.JOIN_STREAM_ID
+import org.schabi.newpipe.database.stream.model.StreamStateEntity.Companion.PLAYBACK_FINISHED_END_MILLISECONDS
+import org.schabi.newpipe.database.stream.model.StreamStateEntity.Companion.STREAM_STATE_TABLE
+
+@Entity(
+ tableName = STREAM_STATE_TABLE,
+ primaryKeys = [JOIN_STREAM_ID],
+ foreignKeys = [
+ ForeignKey(
+ entity = StreamEntity::class,
+ parentColumns = arrayOf(STREAM_ID),
+ childColumns = arrayOf(JOIN_STREAM_ID),
+ onDelete = CASCADE,
+ onUpdate = CASCADE
+ )
+ ]
+)
+data class StreamStateEntity(
+ @ColumnInfo(name = JOIN_STREAM_ID)
+ val streamUid: Long,
+
+ @ColumnInfo(name = STREAM_PROGRESS_MILLIS)
+ val progressMillis: Long
+) {
+ /**
+ * The state will be considered valid, and thus be saved, if the progress is more than
+ * [PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS] or at least 1/4 of the video length.
+ * @param durationInSeconds the duration of the stream connected with this state, in seconds
+ * @return whether this stream state entity should be saved or not
+ */
+ fun isValid(durationInSeconds: Long): Boolean {
+ return progressMillis > PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS ||
+ progressMillis > durationInSeconds * 1000 / 4
+ }
+
+ /**
+ * The video will be considered as finished, if the time left is less than
+ * [PLAYBACK_FINISHED_END_MILLISECONDS] and the progress is at least 3/4 of the video length.
+ * The state will be saved anyway, so that it can be shown under stream info items, but the
+ * player will not resume if a state is considered as finished. Finished streams are also the
+ * ones that can be filtered out in the feed fragment.
+ * @param durationInSeconds the duration of the stream connected with this state, in seconds
+ * @return whether the stream is finished or not
+ */
+ fun isFinished(durationInSeconds: Long): Boolean {
+ return progressMillis >= durationInSeconds * 1000 - PLAYBACK_FINISHED_END_MILLISECONDS &&
+ progressMillis >= durationInSeconds * 1000 * 3 / 4
+ }
+
+ companion object {
+ const val STREAM_STATE_TABLE = "stream_state"
+ const val JOIN_STREAM_ID = "stream_id"
+
+ // This additional field is required for the SQL query because 'stream_id' is used
+ // for some other joins already
+ const val JOIN_STREAM_ID_ALIAS = "stream_id_alias"
+ const val STREAM_PROGRESS_MILLIS = "progress_time"
+
+ /**
+ * Playback state will not be saved, if playback time is less than this threshold
+ * (5000ms = 5s).
+ */
+ const val PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS = 5000L
+
+ /**
+ * Stream will be considered finished if the playback time left exceeds this threshold
+ * (60000ms = 60s).
+ * @see org.schabi.newpipe.database.stream.model.StreamStateEntity.isFinished
+ */
+ const val PLAYBACK_FINISHED_END_MILLISECONDS = 60000L
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/subscription/NotificationMode.java b/app/src/main/java/org/schabi/newpipe/database/subscription/NotificationMode.java
deleted file mode 100644
index 07e0eb7d3..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/subscription/NotificationMode.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.schabi.newpipe.database.subscription;
-
-import androidx.annotation.IntDef;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-@IntDef({NotificationMode.DISABLED, NotificationMode.ENABLED})
-@Retention(RetentionPolicy.SOURCE)
-public @interface NotificationMode {
-
- int DISABLED = 0;
- int ENABLED = 1;
- //other values reserved for the future
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/subscription/NotificationMode.kt b/app/src/main/java/org/schabi/newpipe/database/subscription/NotificationMode.kt
new file mode 100644
index 000000000..f9bb18c0c
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/subscription/NotificationMode.kt
@@ -0,0 +1,18 @@
+/*
+ * SPDX-FileCopyrightText: 2021 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.subscription
+
+import androidx.annotation.IntDef
+
+@IntDef(NotificationMode.Companion.DISABLED, NotificationMode.Companion.ENABLED)
+@Retention(AnnotationRetention.SOURCE)
+annotation class NotificationMode {
+ companion object {
+ const val DISABLED = 0
+ const val ENABLED = 1 // other values reserved for the future
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/database/subscription/SubscriptionDAO.kt b/app/src/main/java/org/schabi/newpipe/database/subscription/SubscriptionDAO.kt
index 47b6f4dd9..e6fdcbf70 100644
--- a/app/src/main/java/org/schabi/newpipe/database/subscription/SubscriptionDAO.kt
+++ b/app/src/main/java/org/schabi/newpipe/database/subscription/SubscriptionDAO.kt
@@ -99,7 +99,7 @@ abstract class SubscriptionDAO : BasicDAO {
if (uidFromInsert != -1L) {
entity.uid = uidFromInsert
} else {
- val subscriptionIdFromDb = getSubscriptionIdInternal(entity.serviceId, entity.url)
+ val subscriptionIdFromDb = getSubscriptionIdInternal(entity.serviceId, entity.url!!)
?: throw IllegalStateException("Subscription cannot be null just after insertion.")
entity.uid = subscriptionIdFromDb
diff --git a/app/src/main/java/org/schabi/newpipe/database/subscription/SubscriptionEntity.java b/app/src/main/java/org/schabi/newpipe/database/subscription/SubscriptionEntity.java
deleted file mode 100644
index df5a3067a..000000000
--- a/app/src/main/java/org/schabi/newpipe/database/subscription/SubscriptionEntity.java
+++ /dev/null
@@ -1,200 +0,0 @@
-package org.schabi.newpipe.database.subscription;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.room.ColumnInfo;
-import androidx.room.Entity;
-import androidx.room.Ignore;
-import androidx.room.Index;
-import androidx.room.PrimaryKey;
-
-import org.schabi.newpipe.extractor.channel.ChannelInfo;
-import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
-import org.schabi.newpipe.util.Constants;
-import org.schabi.newpipe.util.image.ImageStrategy;
-
-import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_SERVICE_ID;
-import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_TABLE;
-import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_URL;
-
-@Entity(tableName = SUBSCRIPTION_TABLE,
- indices = {@Index(value = {SUBSCRIPTION_SERVICE_ID, SUBSCRIPTION_URL}, unique = true)})
-public class SubscriptionEntity {
- public static final String SUBSCRIPTION_UID = "uid";
- public static final String SUBSCRIPTION_TABLE = "subscriptions";
- public static final String SUBSCRIPTION_SERVICE_ID = "service_id";
- public static final String SUBSCRIPTION_URL = "url";
- public static final String SUBSCRIPTION_NAME = "name";
- public static final String SUBSCRIPTION_AVATAR_URL = "avatar_url";
- public static final String SUBSCRIPTION_SUBSCRIBER_COUNT = "subscriber_count";
- public static final String SUBSCRIPTION_DESCRIPTION = "description";
- public static final String SUBSCRIPTION_NOTIFICATION_MODE = "notification_mode";
-
- @PrimaryKey(autoGenerate = true)
- private long uid = 0;
-
- @ColumnInfo(name = SUBSCRIPTION_SERVICE_ID)
- private int serviceId = Constants.NO_SERVICE_ID;
-
- @ColumnInfo(name = SUBSCRIPTION_URL)
- private String url;
-
- @ColumnInfo(name = SUBSCRIPTION_NAME)
- private String name;
-
- @ColumnInfo(name = SUBSCRIPTION_AVATAR_URL)
- private String avatarUrl;
-
- @ColumnInfo(name = SUBSCRIPTION_SUBSCRIBER_COUNT)
- private Long subscriberCount;
-
- @ColumnInfo(name = SUBSCRIPTION_DESCRIPTION)
- private String description;
-
- @ColumnInfo(name = SUBSCRIPTION_NOTIFICATION_MODE)
- private int notificationMode;
-
- @Ignore
- public static SubscriptionEntity from(@NonNull final ChannelInfo info) {
- final SubscriptionEntity result = new SubscriptionEntity();
- result.setServiceId(info.getServiceId());
- result.setUrl(info.getUrl());
- result.setData(info.getName(), ImageStrategy.imageListToDbUrl(info.getAvatars()),
- info.getDescription(), info.getSubscriberCount());
- return result;
- }
-
- public long getUid() {
- return uid;
- }
-
- public void setUid(final long uid) {
- this.uid = uid;
- }
-
- public int getServiceId() {
- return serviceId;
- }
-
- public void setServiceId(final int serviceId) {
- this.serviceId = serviceId;
- }
-
- public String getUrl() {
- return url;
- }
-
- public void setUrl(final String url) {
- this.url = url;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(final String name) {
- this.name = name;
- }
-
- @Nullable
- public String getAvatarUrl() {
- return avatarUrl;
- }
-
- public void setAvatarUrl(@Nullable final String avatarUrl) {
- this.avatarUrl = avatarUrl;
- }
-
- public Long getSubscriberCount() {
- return subscriberCount;
- }
-
- public void setSubscriberCount(final Long subscriberCount) {
- this.subscriberCount = subscriberCount;
- }
-
- public String getDescription() {
- return description;
- }
-
- public void setDescription(final String description) {
- this.description = description;
- }
-
- @NotificationMode
- public int getNotificationMode() {
- return notificationMode;
- }
-
- public void setNotificationMode(@NotificationMode final int notificationMode) {
- this.notificationMode = notificationMode;
- }
-
- @Ignore
- public void setData(final String n, final String au, final String d, final Long sc) {
- this.setName(n);
- this.setAvatarUrl(au);
- this.setDescription(d);
- this.setSubscriberCount(sc);
- }
-
- @Ignore
- public ChannelInfoItem toChannelInfoItem() {
- final ChannelInfoItem item = new ChannelInfoItem(getServiceId(), getUrl(), getName());
- item.setThumbnails(ImageStrategy.dbUrlToImageList(getAvatarUrl()));
- item.setSubscriberCount(getSubscriberCount());
- item.setDescription(getDescription());
- return item;
- }
-
-
- // TODO: Remove these generated methods by migrating this class to a data class from Kotlin.
- @Override
- @SuppressWarnings("EqualsReplaceableByObjectsCall")
- public boolean equals(final Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- final SubscriptionEntity that = (SubscriptionEntity) o;
-
- if (uid != that.uid) {
- return false;
- }
- if (serviceId != that.serviceId) {
- return false;
- }
- if (!url.equals(that.url)) {
- return false;
- }
- if (name != null ? !name.equals(that.name) : that.name != null) {
- return false;
- }
- if (avatarUrl != null ? !avatarUrl.equals(that.avatarUrl) : that.avatarUrl != null) {
- return false;
- }
- if (subscriberCount != null
- ? !subscriberCount.equals(that.subscriberCount)
- : that.subscriberCount != null) {
- return false;
- }
- return description != null
- ? description.equals(that.description)
- : that.description == null;
- }
-
- @Override
- public int hashCode() {
- int result = (int) (uid ^ (uid >>> 32));
- result = 31 * result + serviceId;
- result = 31 * result + url.hashCode();
- result = 31 * result + (name != null ? name.hashCode() : 0);
- result = 31 * result + (avatarUrl != null ? avatarUrl.hashCode() : 0);
- result = 31 * result + (subscriberCount != null ? subscriberCount.hashCode() : 0);
- result = 31 * result + (description != null ? description.hashCode() : 0);
- return result;
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/database/subscription/SubscriptionEntity.kt b/app/src/main/java/org/schabi/newpipe/database/subscription/SubscriptionEntity.kt
new file mode 100644
index 000000000..7df9830e4
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/database/subscription/SubscriptionEntity.kt
@@ -0,0 +1,87 @@
+/*
+ * SPDX-FileCopyrightText: 2017-2024 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.subscription
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.Ignore
+import androidx.room.Index
+import androidx.room.PrimaryKey
+import org.schabi.newpipe.extractor.channel.ChannelInfo
+import org.schabi.newpipe.extractor.channel.ChannelInfoItem
+import org.schabi.newpipe.util.NO_SERVICE_ID
+import org.schabi.newpipe.util.image.ImageStrategy
+
+@Entity(
+ tableName = SubscriptionEntity.Companion.SUBSCRIPTION_TABLE,
+ indices = [
+ Index(
+ value = [SubscriptionEntity.Companion.SUBSCRIPTION_SERVICE_ID, SubscriptionEntity.Companion.SUBSCRIPTION_URL],
+ unique = true
+ )
+ ]
+)
+data class SubscriptionEntity(
+ @PrimaryKey(autoGenerate = true)
+ var uid: Long = 0,
+
+ @ColumnInfo(name = SUBSCRIPTION_SERVICE_ID)
+ var serviceId: Int = NO_SERVICE_ID,
+
+ @ColumnInfo(name = SUBSCRIPTION_URL)
+ var url: String? = null,
+
+ @ColumnInfo(name = SUBSCRIPTION_NAME)
+ var name: String? = null,
+
+ @ColumnInfo(name = SUBSCRIPTION_AVATAR_URL)
+ var avatarUrl: String? = null,
+
+ @ColumnInfo(name = SUBSCRIPTION_SUBSCRIBER_COUNT)
+ var subscriberCount: Long? = null,
+
+ @ColumnInfo(name = SUBSCRIPTION_DESCRIPTION)
+ var description: String? = null,
+
+ @get:NotificationMode
+ @ColumnInfo(name = SUBSCRIPTION_NOTIFICATION_MODE)
+ var notificationMode: Int = 0
+) {
+ @Ignore
+ fun toChannelInfoItem(): ChannelInfoItem {
+ return ChannelInfoItem(this.serviceId, this.url, this.name).apply {
+ thumbnails = ImageStrategy.dbUrlToImageList(this@SubscriptionEntity.avatarUrl)
+ subscriberCount = this@SubscriptionEntity.subscriberCount ?: -1
+ description = this@SubscriptionEntity.description
+ }
+ }
+
+ companion object {
+ const val SUBSCRIPTION_UID: String = "uid"
+ const val SUBSCRIPTION_TABLE: String = "subscriptions"
+ const val SUBSCRIPTION_SERVICE_ID: String = "service_id"
+ const val SUBSCRIPTION_URL: String = "url"
+ const val SUBSCRIPTION_NAME: String = "name"
+ const val SUBSCRIPTION_AVATAR_URL: String = "avatar_url"
+ const val SUBSCRIPTION_SUBSCRIBER_COUNT: String = "subscriber_count"
+ const val SUBSCRIPTION_DESCRIPTION: String = "description"
+ const val SUBSCRIPTION_NOTIFICATION_MODE: String = "notification_mode"
+
+ @JvmStatic
+ @Ignore
+ fun from(info: ChannelInfo): SubscriptionEntity {
+ return SubscriptionEntity(
+ serviceId = info.serviceId,
+ url = info.url,
+ name = info.name,
+ avatarUrl = ImageStrategy.imageListToDbUrl(info.avatars),
+ description = info.description,
+ subscriberCount = info.subscriberCount
+ )
+ }
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java
index 003aa5893..741bda246 100644
--- a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java
+++ b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java
@@ -389,8 +389,7 @@ public class DownloadDialog extends DialogFragment
}
}, throwable -> ErrorUtil.showSnackbar(context,
new ErrorInfo(throwable, UserAction.DOWNLOAD_OPEN_DIALOG,
- "Downloading video stream size",
- currentInfo.getServiceId()))));
+ "Downloading video stream size", currentInfo))));
disposables.add(StreamInfoWrapper.fetchMoreInfoForWrapper(getWrappedAudioStreams())
.subscribe(result -> {
if (dialogBinding.videoAudioGroup.getCheckedRadioButtonId()
@@ -399,8 +398,7 @@ public class DownloadDialog extends DialogFragment
}
}, throwable -> ErrorUtil.showSnackbar(context,
new ErrorInfo(throwable, UserAction.DOWNLOAD_OPEN_DIALOG,
- "Downloading audio stream size",
- currentInfo.getServiceId()))));
+ "Downloading audio stream size", currentInfo))));
disposables.add(StreamInfoWrapper.fetchMoreInfoForWrapper(wrappedSubtitleStreams)
.subscribe(result -> {
if (dialogBinding.videoAudioGroup.getCheckedRadioButtonId()
@@ -409,8 +407,7 @@ public class DownloadDialog extends DialogFragment
}
}, throwable -> ErrorUtil.showSnackbar(context,
new ErrorInfo(throwable, UserAction.DOWNLOAD_OPEN_DIALOG,
- "Downloading subtitle stream size",
- currentInfo.getServiceId()))));
+ "Downloading subtitle stream size", currentInfo))));
}
private void setupAudioTrackSpinner() {
@@ -1136,7 +1133,7 @@ public class DownloadDialog extends DialogFragment
}
DownloadManagerService.startMission(context, urls, storage, kind, threads,
- currentInfo.getUrl(), psName, psArgs, nearLength, new ArrayList<>(recoveryInfo));
+ currentInfo, psName, psArgs, nearLength, new ArrayList<>(recoveryInfo));
Toast.makeText(context, getString(R.string.download_has_started),
Toast.LENGTH_SHORT).show();
diff --git a/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java b/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java
index 4d9966364..90d8f4797 100644
--- a/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java
+++ b/app/src/main/java/org/schabi/newpipe/error/AcraReportSender.java
@@ -36,8 +36,8 @@ public class AcraReportSender implements ReportSender {
ErrorUtil.openActivity(context, new ErrorInfo(
new String[]{report.getString(ReportField.STACK_TRACE)},
UserAction.UI_ERROR,
- ErrorInfo.SERVICE_NONE,
"ACRA report",
+ null,
R.string.app_ui_crash));
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java
index a07b9b0b5..160dcca4d 100644
--- a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java
@@ -115,7 +115,7 @@ public class ErrorActivity extends AppCompatActivity {
// normal bugreport
buildInfo(errorInfo);
- activityErrorBinding.errorMessageView.setText(errorInfo.getMessageStringId());
+ activityErrorBinding.errorMessageView.setText(errorInfo.getMessage(this));
activityErrorBinding.errorView.setText(formErrorText(errorInfo.getStackTraces()));
// print stack trace once again for debugging:
diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt
index 6d8c1bd63..609fbb336 100644
--- a/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt
+++ b/app/src/main/java/org/schabi/newpipe/error/ErrorInfo.kt
@@ -1,115 +1,304 @@
package org.schabi.newpipe.error
+import android.content.Context
import android.os.Parcelable
import androidx.annotation.StringRes
+import androidx.core.content.ContextCompat
import com.google.android.exoplayer2.ExoPlaybackException
-import kotlinx.parcelize.IgnoredOnParcel
+import com.google.android.exoplayer2.upstream.HttpDataSource
+import com.google.android.exoplayer2.upstream.Loader
import kotlinx.parcelize.Parcelize
import org.schabi.newpipe.R
import org.schabi.newpipe.extractor.Info
+import org.schabi.newpipe.extractor.ServiceList
+import org.schabi.newpipe.extractor.ServiceList.YouTube
import org.schabi.newpipe.extractor.exceptions.AccountTerminatedException
+import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException
import org.schabi.newpipe.extractor.exceptions.ExtractionException
+import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException
+import org.schabi.newpipe.extractor.exceptions.PaidContentException
+import org.schabi.newpipe.extractor.exceptions.PrivateContentException
+import org.schabi.newpipe.extractor.exceptions.ReCaptchaException
+import org.schabi.newpipe.extractor.exceptions.SignInConfirmNotBotException
+import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException
+import org.schabi.newpipe.extractor.exceptions.UnsupportedContentInCountryException
+import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentException
import org.schabi.newpipe.ktx.isNetworkRelated
-import org.schabi.newpipe.util.ServiceHelper
+import org.schabi.newpipe.player.mediasource.FailedMediaSource
+import org.schabi.newpipe.player.resolver.PlaybackResolver
+import java.net.UnknownHostException
+/**
+ * An error has occurred in the app. This class contains plain old parcelable data that can be used
+ * to report the error and to show it to the user along with correct action buttons.
+ */
@Parcelize
-class ErrorInfo(
+class ErrorInfo private constructor(
val stackTraces: Array,
val userAction: UserAction,
- val serviceName: String,
val request: String,
- val messageStringId: Int
+ val serviceId: Int?,
+ private val message: ErrorMessage,
+ /**
+ * If `true`, a report button will be shown for this error. Otherwise the error is not something
+ * that can really be reported (e.g. a network issue, or content not being available at all).
+ */
+ val isReportable: Boolean,
+ /**
+ * If `true`, the process causing this error can be retried, otherwise not.
+ */
+ val isRetryable: Boolean,
+ /**
+ * If present, indicates that the exception was a ReCaptchaException, and this is the URL
+ * provided by the service that can be used to solve the ReCaptcha challenge.
+ */
+ val recaptchaUrl: String?,
+ /**
+ * If present, this resource can alternatively be opened in browser (useful if NewPipe is
+ * badly broken).
+ */
+ val openInBrowserUrl: String?,
) : Parcelable {
- // no need to store throwable, all data for report is in other variables
- // also, the throwable might not be serializable, see TeamNewPipe/NewPipe#7302
- @IgnoredOnParcel
- var throwable: Throwable? = null
-
- private constructor(
+ @JvmOverloads
+ constructor(
throwable: Throwable,
userAction: UserAction,
- serviceName: String,
- request: String
+ request: String,
+ serviceId: Int? = null,
+ openInBrowserUrl: String? = null,
) : this(
throwableToStringList(throwable),
userAction,
- serviceName,
request,
- getMessageStringId(throwable, userAction)
- ) {
- this.throwable = throwable
- }
+ serviceId,
+ getMessage(throwable, userAction, serviceId),
+ isReportable(throwable),
+ isRetryable(throwable),
+ (throwable as? ReCaptchaException)?.url,
+ openInBrowserUrl,
+ )
- private constructor(
- throwable: List,
+ @JvmOverloads
+ constructor(
+ throwables: List,
userAction: UserAction,
- serviceName: String,
- request: String
+ request: String,
+ serviceId: Int? = null,
+ openInBrowserUrl: String? = null,
) : this(
- throwableListToStringList(throwable),
+ throwableListToStringList(throwables),
userAction,
- serviceName,
request,
- getMessageStringId(throwable.firstOrNull(), userAction)
- ) {
- this.throwable = throwable.firstOrNull()
+ serviceId,
+ getMessage(throwables.firstOrNull(), userAction, serviceId),
+ throwables.any(::isReportable),
+ throwables.isEmpty() || throwables.any(::isRetryable),
+ throwables.firstNotNullOfOrNull { it as? ReCaptchaException }?.url,
+ openInBrowserUrl,
+ )
+
+ // constructor to manually build ErrorInfo when no throwable is available
+ constructor(
+ stackTraces: Array,
+ userAction: UserAction,
+ request: String,
+ serviceId: Int?,
+ @StringRes message: Int
+ ) :
+ this(
+ stackTraces, userAction, request, serviceId, ErrorMessage(message),
+ true, false, null, null
+ )
+
+ // constructor with only one throwable to extract service id and openInBrowserUrl from an Info
+ constructor(
+ throwable: Throwable,
+ userAction: UserAction,
+ request: String,
+ info: Info?,
+ ) :
+ this(throwable, userAction, request, info?.serviceId, info?.url)
+
+ // constructor with multiple throwables to extract service id and openInBrowserUrl from an Info
+ constructor(
+ throwables: List,
+ userAction: UserAction,
+ request: String,
+ info: Info?,
+ ) :
+ this(throwables, userAction, request, info?.serviceId, info?.url)
+
+ fun getServiceName(): String {
+ return getServiceName(serviceId)
}
- // constructors with single throwable
- constructor(throwable: Throwable, userAction: UserAction, request: String) :
- this(throwable, userAction, SERVICE_NONE, request)
- constructor(throwable: Throwable, userAction: UserAction, request: String, serviceId: Int) :
- this(throwable, userAction, ServiceHelper.getNameOfServiceById(serviceId), request)
- constructor(throwable: Throwable, userAction: UserAction, request: String, info: Info?) :
- this(throwable, userAction, getInfoServiceName(info), request)
-
- // constructors with list of throwables
- constructor(throwable: List, userAction: UserAction, request: String) :
- this(throwable, userAction, SERVICE_NONE, request)
- constructor(throwable: List, userAction: UserAction, request: String, serviceId: Int) :
- this(throwable, userAction, ServiceHelper.getNameOfServiceById(serviceId), request)
- constructor(throwable: List, userAction: UserAction, request: String, info: Info?) :
- this(throwable, userAction, getInfoServiceName(info), request)
+ fun getMessage(context: Context): String {
+ return message.getString(context)
+ }
companion object {
- const val SERVICE_NONE = "none"
+ @Parcelize
+ class ErrorMessage(
+ @StringRes
+ private val stringRes: Int,
+ private vararg val formatArgs: String,
+ ) : Parcelable {
+ fun getString(context: Context): String {
+ return if (formatArgs.isEmpty()) {
+ // use ContextCompat.getString() just in case context is not AppCompatActivity
+ ContextCompat.getString(context, stringRes)
+ } else {
+ // ContextCompat.getString() with formatArgs does not exist, so we just
+ // replicate its source code but with formatArgs
+ ContextCompat.getContextForLanguage(context).getString(stringRes, *formatArgs)
+ }
+ }
+ }
+
+ const val SERVICE_NONE = ""
+
+ private fun getServiceName(serviceId: Int?) =
+ // not using getNameOfServiceById since we want to accept a nullable serviceId and we
+ // want to default to SERVICE_NONE
+ ServiceList.all()?.firstOrNull { it.serviceId == serviceId }?.serviceInfo?.name
+ ?: SERVICE_NONE
fun throwableToStringList(throwable: Throwable) = arrayOf(throwable.stackTraceToString())
fun throwableListToStringList(throwableList: List) =
throwableList.map { it.stackTraceToString() }.toTypedArray()
- private fun getInfoServiceName(info: Info?) =
- if (info == null) SERVICE_NONE else ServiceHelper.getNameOfServiceById(info.serviceId)
-
- @StringRes
- private fun getMessageStringId(
+ fun getMessage(
throwable: Throwable?,
- action: UserAction
- ): Int {
+ action: UserAction?,
+ serviceId: Int?,
+ ): ErrorMessage {
return when {
- throwable is AccountTerminatedException -> R.string.account_terminated
- throwable is ContentNotAvailableException -> R.string.content_not_available
- throwable != null && throwable.isNetworkRelated -> R.string.network_error
- throwable is ContentNotSupportedException -> R.string.content_not_supported
- throwable is ExtractionException -> R.string.parsing_error
+ // player exceptions
+ // some may be IOException, so do these checks before isNetworkRelated!
throwable is ExoPlaybackException -> {
- when (throwable.type) {
- ExoPlaybackException.TYPE_SOURCE -> R.string.player_stream_failure
- ExoPlaybackException.TYPE_UNEXPECTED -> R.string.player_recoverable_failure
- else -> R.string.player_unrecoverable_failure
+ val cause = throwable.cause
+ when {
+ cause is HttpDataSource.InvalidResponseCodeException -> {
+ if (cause.responseCode == 403) {
+ if (serviceId == YouTube.serviceId) {
+ ErrorMessage(R.string.youtube_player_http_403)
+ } else {
+ ErrorMessage(R.string.player_http_403)
+ }
+ } else {
+ ErrorMessage(R.string.player_http_invalid_status, cause.responseCode.toString())
+ }
+ }
+ cause is Loader.UnexpectedLoaderException && cause.cause is ExtractionException ->
+ getMessage(throwable, action, serviceId)
+ throwable.type == ExoPlaybackException.TYPE_SOURCE ->
+ ErrorMessage(R.string.player_stream_failure)
+ throwable.type == ExoPlaybackException.TYPE_UNEXPECTED ->
+ ErrorMessage(R.string.player_recoverable_failure)
+ else ->
+ ErrorMessage(R.string.player_unrecoverable_failure)
}
}
- action == UserAction.UI_ERROR -> R.string.app_ui_crash
- action == UserAction.REQUESTED_COMMENTS -> R.string.error_unable_to_load_comments
- action == UserAction.SUBSCRIPTION_CHANGE -> R.string.subscription_change_failed
- action == UserAction.SUBSCRIPTION_UPDATE -> R.string.subscription_update_failed
- action == UserAction.LOAD_IMAGE -> R.string.could_not_load_thumbnails
- action == UserAction.DOWNLOAD_OPEN_DIALOG -> R.string.could_not_setup_download_menu
- else -> R.string.general_error
+ throwable is FailedMediaSource.FailedMediaSourceException ->
+ getMessage(throwable.cause, action, serviceId)
+ throwable is PlaybackResolver.ResolverException ->
+ ErrorMessage(R.string.player_stream_failure)
+
+ // content not available exceptions
+ throwable is AccountTerminatedException ->
+ throwable.message
+ ?.takeIf { reason -> !reason.isEmpty() }
+ ?.let { reason ->
+ ErrorMessage(
+ R.string.account_terminated_service_provides_reason,
+ getServiceName(serviceId),
+ reason
+ )
+ }
+ ?: ErrorMessage(R.string.account_terminated)
+ throwable is AgeRestrictedContentException ->
+ ErrorMessage(R.string.restricted_video_no_stream)
+ throwable is GeographicRestrictionException ->
+ ErrorMessage(R.string.georestricted_content)
+ throwable is PaidContentException ->
+ ErrorMessage(R.string.paid_content)
+ throwable is PrivateContentException ->
+ ErrorMessage(R.string.private_content)
+ throwable is SoundCloudGoPlusContentException ->
+ ErrorMessage(R.string.soundcloud_go_plus_content)
+ throwable is UnsupportedContentInCountryException ->
+ ErrorMessage(R.string.unsupported_content_in_country)
+ throwable is YoutubeMusicPremiumContentException ->
+ ErrorMessage(R.string.youtube_music_premium_content)
+ throwable is SignInConfirmNotBotException ->
+ ErrorMessage(R.string.sign_in_confirm_not_bot_error, getServiceName(serviceId))
+ throwable is ContentNotAvailableException ->
+ ErrorMessage(R.string.content_not_available)
+
+ // other extractor exceptions
+ throwable is ContentNotSupportedException ->
+ ErrorMessage(R.string.content_not_supported)
+ // ReCaptchas will be handled in a special way anyway
+ throwable is ReCaptchaException ->
+ ErrorMessage(R.string.recaptcha_request_toast)
+ // test this at the end as many exceptions could be a subclass of IOException
+ throwable != null && throwable.isNetworkRelated ->
+ ErrorMessage(R.string.network_error)
+ // an extraction exception unrelated to the network
+ // is likely an issue with parsing the website
+ throwable is ExtractionException ->
+ ErrorMessage(R.string.parsing_error)
+
+ // user actions (in case the exception is null or unrecognizable)
+ action == UserAction.UI_ERROR ->
+ ErrorMessage(R.string.app_ui_crash)
+ action == UserAction.REQUESTED_COMMENTS ->
+ ErrorMessage(R.string.error_unable_to_load_comments)
+ action == UserAction.SUBSCRIPTION_CHANGE ->
+ ErrorMessage(R.string.subscription_change_failed)
+ action == UserAction.SUBSCRIPTION_UPDATE ->
+ ErrorMessage(R.string.subscription_update_failed)
+ action == UserAction.LOAD_IMAGE ->
+ ErrorMessage(R.string.could_not_load_thumbnails)
+ action == UserAction.DOWNLOAD_OPEN_DIALOG ->
+ ErrorMessage(R.string.could_not_setup_download_menu)
+ else ->
+ ErrorMessage(R.string.error_snackbar_message)
+ }
+ }
+
+ fun isReportable(throwable: Throwable?): Boolean {
+ return when (throwable) {
+ // we don't have an exception, so this is a manually built error, which likely
+ // indicates that it's important and is thus reportable
+ null -> true
+ // the service explicitly said that content is not available (e.g. age restrictions,
+ // video deleted, etc.), there is no use in letting users report it
+ is ContentNotAvailableException -> false
+ // we know the content is not supported, no need to let the user report it
+ is ContentNotSupportedException -> false
+ // happens often when there is no internet connection; we don't use
+ // `throwable.isNetworkRelated` since any `IOException` would make that function
+ // return true, but not all `IOException`s are network related
+ is UnknownHostException -> false
+ // by default, this is an unexpected exception, which the user could report
+ else -> true
+ }
+ }
+
+ fun isRetryable(throwable: Throwable?): Boolean {
+ return when (throwable) {
+ // we know the content is not available, retrying won't help
+ is ContentNotAvailableException -> false
+ // we know the content is not supported, retrying won't help
+ is ContentNotSupportedException -> false
+ // by default (including if throwable is null), enable retrying (though the retry
+ // button will be shown only if a way to perform the retry is implemented)
+ else -> true
}
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt
index 14ec41148..4ec5f58c3 100644
--- a/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt
+++ b/app/src/main/java/org/schabi/newpipe/error/ErrorPanelHelper.kt
@@ -2,7 +2,6 @@ package org.schabi.newpipe.error
import android.content.Context
import android.content.Intent
-import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.TextView
@@ -14,21 +13,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.Disposable
import org.schabi.newpipe.MainActivity
import org.schabi.newpipe.R
-import org.schabi.newpipe.extractor.exceptions.AccountTerminatedException
-import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException
-import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException
-import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException
-import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException
-import org.schabi.newpipe.extractor.exceptions.PaidContentException
-import org.schabi.newpipe.extractor.exceptions.PrivateContentException
-import org.schabi.newpipe.extractor.exceptions.ReCaptchaException
-import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException
-import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentException
-import org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty
import org.schabi.newpipe.ktx.animate
-import org.schabi.newpipe.ktx.isInterruptedCaused
-import org.schabi.newpipe.ktx.isNetworkRelated
-import org.schabi.newpipe.util.ServiceHelper
import org.schabi.newpipe.util.external_communication.ShareUtils
import java.util.concurrent.TimeUnit
@@ -78,64 +63,32 @@ class ErrorPanelHelper(
}
fun showError(errorInfo: ErrorInfo) {
-
- if (errorInfo.throwable != null && errorInfo.throwable!!.isInterruptedCaused) {
- if (DEBUG) {
- Log.w(TAG, "onError() isInterruptedCaused! = [$errorInfo.throwable]")
- }
- return
- }
-
ensureDefaultVisibility()
+ errorTextView.text = errorInfo.getMessage(context)
- if (errorInfo.throwable is ReCaptchaException) {
- errorTextView.setText(R.string.recaptcha_request_toast)
-
- showAndSetErrorButtonAction(
- R.string.recaptcha_solve
- ) {
+ if (errorInfo.recaptchaUrl != null) {
+ showAndSetErrorButtonAction(R.string.recaptcha_solve) {
// Starting ReCaptcha Challenge Activity
val intent = Intent(context, ReCaptchaActivity::class.java)
- intent.putExtra(
- ReCaptchaActivity.RECAPTCHA_URL_EXTRA,
- (errorInfo.throwable as ReCaptchaException).url
- )
+ intent.putExtra(ReCaptchaActivity.RECAPTCHA_URL_EXTRA, errorInfo.recaptchaUrl)
fragment.startActivityForResult(intent, ReCaptchaActivity.RECAPTCHA_REQUEST)
errorActionButton.setOnClickListener(null)
}
-
- errorRetryButton.isVisible = retryShouldBeShown
- showAndSetOpenInBrowserButtonAction(errorInfo)
- } else if (errorInfo.throwable is AccountTerminatedException) {
- errorTextView.setText(R.string.account_terminated)
-
- if (!isNullOrEmpty((errorInfo.throwable as AccountTerminatedException).message)) {
- errorServiceInfoTextView.text = context.resources.getString(
- R.string.service_provides_reason,
- ServiceHelper.getSelectedService(context)?.serviceInfo?.name ?: ""
- )
- errorServiceInfoTextView.isVisible = true
-
- errorServiceExplanationTextView.text =
- (errorInfo.throwable as AccountTerminatedException).message
- errorServiceExplanationTextView.isVisible = true
- }
- } else {
- showAndSetErrorButtonAction(
- R.string.error_snackbar_action
- ) {
+ } else if (errorInfo.isReportable) {
+ showAndSetErrorButtonAction(R.string.error_snackbar_action) {
ErrorUtil.openActivity(context, errorInfo)
}
+ }
- errorTextView.setText(getExceptionDescription(errorInfo.throwable))
+ if (errorInfo.isRetryable) {
+ errorRetryButton.isVisible = retryShouldBeShown
+ }
- if (errorInfo.throwable !is ContentNotAvailableException &&
- errorInfo.throwable !is ContentNotSupportedException
- ) {
- // show retry button only for content which is not unavailable or unsupported
- errorRetryButton.isVisible = retryShouldBeShown
+ if (errorInfo.openInBrowserUrl != null) {
+ errorOpenInBrowserButton.isVisible = true
+ errorOpenInBrowserButton.setOnClickListener {
+ ShareUtils.openUrlInBrowser(context, errorInfo.openInBrowserUrl)
}
- showAndSetOpenInBrowserButtonAction(errorInfo)
}
setRootVisible()
@@ -153,15 +106,6 @@ class ErrorPanelHelper(
errorActionButton.setOnClickListener(listener)
}
- fun showAndSetOpenInBrowserButtonAction(
- errorInfo: ErrorInfo
- ) {
- errorOpenInBrowserButton.isVisible = true
- errorOpenInBrowserButton.setOnClickListener {
- ShareUtils.openUrlInBrowser(context, errorInfo.request)
- }
- }
-
fun showTextError(errorString: String) {
ensureDefaultVisibility()
@@ -192,27 +136,5 @@ class ErrorPanelHelper(
companion object {
val TAG: String = ErrorPanelHelper::class.simpleName!!
val DEBUG: Boolean = MainActivity.DEBUG
-
- @StringRes
- fun getExceptionDescription(throwable: Throwable?): Int {
- return when (throwable) {
- is AgeRestrictedContentException -> R.string.restricted_video_no_stream
- is GeographicRestrictionException -> R.string.georestricted_content
- is PaidContentException -> R.string.paid_content
- is PrivateContentException -> R.string.private_content
- is SoundCloudGoPlusContentException -> R.string.soundcloud_go_plus_content
- is YoutubeMusicPremiumContentException -> R.string.youtube_music_premium_content
- is ContentNotAvailableException -> R.string.content_not_available
- is ContentNotSupportedException -> R.string.content_not_supported
- else -> {
- // show retry button only for content which is not unavailable or unsupported
- if (throwable != null && throwable.isNetworkRelated) {
- R.string.network_error
- } else {
- R.string.error_snackbar_message
- }
- }
- }
- }
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt
index 93dd8e522..b358a5fd2 100644
--- a/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt
+++ b/app/src/main/java/org/schabi/newpipe/error/ErrorUtil.kt
@@ -10,6 +10,7 @@ import android.widget.Toast
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.PendingIntentCompat
+import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.preference.PreferenceManager
import com.google.android.material.snackbar.Snackbar
@@ -121,7 +122,7 @@ class ErrorUtil {
)
.setSmallIcon(R.drawable.ic_bug_report)
.setContentTitle(context.getString(R.string.error_report_notification_title))
- .setContentText(context.getString(errorInfo.messageStringId))
+ .setContentText(errorInfo.getMessage(context))
.setAutoCancel(true)
.setContentIntent(
PendingIntentCompat.getActivity(
@@ -136,9 +137,11 @@ class ErrorUtil {
NotificationManagerCompat.from(context)
.notify(ERROR_REPORT_NOTIFICATION_ID, notificationBuilder.build())
- // since the notification is silent, also show a toast, otherwise the user is confused
- Toast.makeText(context, R.string.error_report_notification_toast, Toast.LENGTH_SHORT)
- .show()
+ ContextCompat.getMainExecutor(context).execute {
+ // since the notification is silent, also show a toast, otherwise the user is confused
+ Toast.makeText(context, R.string.error_report_notification_toast, Toast.LENGTH_SHORT)
+ .show()
+ }
}
private fun getErrorActivityIntent(context: Context, errorInfo: ErrorInfo): Intent {
@@ -153,10 +156,10 @@ class ErrorUtil {
// fallback to showing a notification if no root view is available
createNotification(context, errorInfo)
} else {
- Snackbar.make(rootView, R.string.error_snackbar_message, Snackbar.LENGTH_LONG)
+ Snackbar.make(rootView, errorInfo.getMessage(context), Snackbar.LENGTH_LONG)
.setActionTextColor(Color.YELLOW)
.setAction(context.getString(R.string.error_snackbar_action).uppercase()) {
- openActivity(context, errorInfo)
+ context.startActivity(getErrorActivityIntent(context, errorInfo))
}.show()
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/error/UserAction.java b/app/src/main/java/org/schabi/newpipe/error/UserAction.java
index afb880a29..d3af9d32e 100644
--- a/app/src/main/java/org/schabi/newpipe/error/UserAction.java
+++ b/app/src/main/java/org/schabi/newpipe/error/UserAction.java
@@ -33,7 +33,9 @@ public enum UserAction {
SHARE_TO_NEWPIPE("share to newpipe"),
CHECK_FOR_NEW_APP_VERSION("check for new app version"),
OPEN_INFO_ITEM_DIALOG("open info item dialog"),
- GETTING_MAIN_SCREEN_TAB("getting main screen tab");
+ GETTING_MAIN_SCREEN_TAB("getting main screen tab"),
+ PLAY_ON_POPUP("play on popup"),
+ SUBSCRIPTIONS("loading subscriptions");
private final String message;
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
index 083d1fe05..9bffa149c 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
@@ -93,6 +93,7 @@ import org.schabi.newpipe.local.dialog.PlaylistDialog;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.local.playlist.LocalPlaylistFragment;
import org.schabi.newpipe.player.Player;
+import org.schabi.newpipe.player.PlayerIntentType;
import org.schabi.newpipe.player.PlayerService;
import org.schabi.newpipe.player.PlayerType;
import org.schabi.newpipe.player.event.OnKeyDownListener;
@@ -205,6 +206,8 @@ public final class VideoDetailFragment
int lastStableBottomSheetState = BottomSheetBehavior.STATE_EXPANDED;
@State
protected boolean autoPlayEnabled = true;
+ @State
+ protected int originalOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@Nullable
private StreamInfo currentInfo = null;
@@ -876,7 +879,7 @@ public final class VideoDetailFragment
}
}
}, throwable -> showError(new ErrorInfo(throwable, UserAction.REQUESTED_STREAM,
- url == null ? "no url" : url, serviceId)));
+ url == null ? "no url" : url, serviceId, url)));
}
/*//////////////////////////////////////////////////////////////////////////
@@ -1166,8 +1169,12 @@ public final class VideoDetailFragment
final PlayQueue queue = setupPlayQueueForIntent(false);
tryAddVideoPlayerView();
- final Intent playerIntent = NavigationHelper.getPlayerIntent(requireContext(),
- PlayerService.class, queue, true, autoPlayEnabled);
+ final Context context = requireContext();
+ final Intent playerIntent =
+ NavigationHelper.getPlayerIntent(context, PlayerService.class, queue,
+ PlayerIntentType.AllOthers)
+ .putExtra(Player.PLAY_WHEN_READY, autoPlayEnabled)
+ .putExtra(Player.RESUME_PLAYBACK, true);
ContextCompat.startForegroundService(activity, playerIntent);
}
@@ -1225,7 +1232,13 @@ public final class VideoDetailFragment
disposables.add(recordManager.onViewed(info).onErrorComplete()
.subscribe(
ignored -> { /* successful */ },
- error -> Log.e(TAG, "Register view failure: ", error)
+ error -> showSnackBarError(
+ new ErrorInfo(
+ error,
+ UserAction.PLAY_STREAM,
+ "Got an error when modifying history on viewed"
+ )
+ )
));
}
@@ -1411,10 +1424,8 @@ public final class VideoDetailFragment
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
// Rebound to the service if it was closed via notification or mini player
- if (!playerHolder.isBound()) {
- playerHolder.startService(
- false, VideoDetailFragment.this);
- }
+ playerHolder.setListener(VideoDetailFragment.this);
+ playerHolder.tryBindIfNeeded(context);
break;
}
}
@@ -1423,7 +1434,8 @@ public final class VideoDetailFragment
intentFilter.addAction(ACTION_SHOW_MAIN_PLAYER);
intentFilter.addAction(ACTION_HIDE_MAIN_PLAYER);
intentFilter.addAction(ACTION_PLAYER_STARTED);
- activity.registerReceiver(broadcastReceiver, intentFilter);
+ ContextCompat.registerReceiver(activity, broadcastReceiver, intentFilter,
+ ContextCompat.RECEIVER_EXPORTED);
}
@@ -1592,8 +1604,8 @@ public final class VideoDetailFragment
}
if (!info.getErrors().isEmpty()) {
- showSnackBarError(new ErrorInfo(info.getErrors(),
- UserAction.REQUESTED_STREAM, info.getUrl(), info));
+ showSnackBarError(new ErrorInfo(info.getErrors(), UserAction.REQUESTED_STREAM,
+ "Some info not extracted: " + info.getUrl(), info));
}
}
@@ -1896,22 +1908,29 @@ public final class VideoDetailFragment
@Override
public void onScreenRotationButtonClicked() {
- // In tablet user experience will be better if screen will not be rotated
- // from landscape to portrait every time.
- // Just turn on fullscreen mode in landscape orientation
- // or portrait & unlocked global orientation
- final boolean isLandscape = DeviceUtils.isLandscape(requireContext());
- if (DeviceUtils.isTablet(activity)
- && (!globalScreenOrientationLocked(activity) || isLandscape)) {
- player.UIs().get(MainPlayerUi.class).ifPresent(MainPlayerUi::toggleFullscreen);
+ final Optional playerUi = player != null
+ ? player.UIs().get(MainPlayerUi.class)
+ : Optional.empty();
+ if (playerUi.isEmpty()) {
return;
}
- final int newOrientation = isLandscape
- ? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
- : ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
+ // On tablets and TVs, just toggle fullscreen UI without orientation change.
+ if (DeviceUtils.isTablet(activity) || DeviceUtils.isTv(activity)) {
+ playerUi.get().toggleFullscreen();
+ return;
+ }
- activity.setRequestedOrientation(newOrientation);
+ if (playerUi.get().isFullscreen()) {
+ // EXITING FULLSCREEN
+ playerUi.get().toggleFullscreen();
+ activity.setRequestedOrientation(originalOrientation);
+ } else {
+ // ENTERING FULLSCREEN
+ originalOrientation = activity.getRequestedOrientation();
+ playerUi.get().toggleFullscreen();
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
+ }
}
/*
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java
index 7f594734a..848dfe6f5 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListInfoFragment.java
@@ -153,7 +153,7 @@ public abstract class BaseListInfoFragment
showError(new ErrorInfo(throwable, errorUserAction,
- "Start loading: " + url, serviceId)));
+ "Start loading: " + url, serviceId, url)));
}
/**
@@ -184,7 +184,7 @@ public abstract class BaseListInfoFragment
dynamicallyShowErrorPanelOrSnackbar(new ErrorInfo(throwable,
- errorUserAction, "Loading more items: " + url, serviceId)));
+ errorUserAction, "Loading more items: " + url, serviceId, url)));
}
private void forbidDownwardFocusScroll() {
@@ -210,7 +210,7 @@ public abstract class BaseListInfoFragment
final SubscriptionEntity channel = new SubscriptionEntity();
channel.setServiceId(info.getServiceId());
channel.setUrl(info.getUrl());
- channel.setData(info.getName(),
- ImageStrategy.imageListToDbUrl(info.getAvatars()),
- info.getDescription(),
- info.getSubscriberCount());
+ channel.setName(info.getName());
+ channel.setAvatarUrl(ImageStrategy.imageListToDbUrl(info.getAvatars()));
+ channel.setDescription(info.getDescription());
+ channel.setSubscriberCount(info.getSubscriberCount());
channelSubscription = null;
updateNotifyButton(null);
subscribeButtonMonitor = monitorSubscribeButton(mapOnSubscribe(channel));
@@ -577,7 +577,7 @@ public class ChannelFragment extends BaseStateFragment
isLoading.set(false);
handleResult(result);
}, throwable -> showError(new ErrorInfo(throwable, UserAction.REQUESTED_CHANNEL,
- url == null ? "No URL" : url, serviceId)));
+ url == null ? "No URL" : url, serviceId, url)));
}
@Override
diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
index cea06b942..8cb5f6497 100644
--- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java
@@ -54,6 +54,7 @@ import org.schabi.newpipe.extractor.MetaInfo;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService;
+import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.search.SearchExtractor;
import org.schabi.newpipe.extractor.search.SearchInfo;
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory;
@@ -934,7 +935,21 @@ public class SearchFragment extends BaseListFragment {
+ private static final class SuggestionItemCallback
+ extends DiffUtil.ItemCallback {
@Override
public boolean areItemsTheSame(@NonNull final SuggestionItem oldItem,
@NonNull final SuggestionItem newItem) {
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/dialog/StreamDialogDefaultEntry.java b/app/src/main/java/org/schabi/newpipe/info_list/dialog/StreamDialogDefaultEntry.java
index c7ac9556f..a2bf4a1ff 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/dialog/StreamDialogDefaultEntry.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/dialog/StreamDialogDefaultEntry.java
@@ -13,6 +13,9 @@ import androidx.annotation.StringRes;
import org.schabi.newpipe.R;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.download.DownloadDialog;
+import org.schabi.newpipe.error.ErrorInfo;
+import org.schabi.newpipe.error.ErrorUtil;
+import org.schabi.newpipe.error.UserAction;
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
import org.schabi.newpipe.local.dialog.PlaylistDialog;
import org.schabi.newpipe.local.history.HistoryRecordManager;
@@ -132,6 +135,16 @@ public enum StreamDialogDefaultEntry {
MARK_AS_WATCHED(R.string.mark_as_watched, (fragment, item) ->
new HistoryRecordManager(fragment.getContext())
.markAsWatched(item)
+ .doOnError(error -> {
+ ErrorUtil.showSnackbar(
+ fragment.requireContext(),
+ new ErrorInfo(
+ error,
+ UserAction.OPEN_INFO_ITEM_DIALOG,
+ "Got an error when trying to mark as watched"
+ )
+ );
+ })
.onErrorComplete()
.observeOn(AndroidSchedulers.mainThread())
.subscribe()
diff --git a/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java b/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java
index a5e1594d1..1f3772dd5 100644
--- a/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/local/bookmark/BookmarkFragment.java
@@ -1,6 +1,7 @@
package org.schabi.newpipe.local.bookmark;
import static org.schabi.newpipe.local.bookmark.MergedPlaylistManager.getMergedOrderedPlaylists;
+import static org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout;
import android.content.DialogInterface;
import android.os.Bundle;
@@ -140,7 +141,7 @@ public final class BookmarkFragment extends BaseLocalListFragment playlists) {
return playlists.stream()
- .anyMatch(playlist -> playlist.timesStreamIsContained > 0);
+ .anyMatch(playlist -> playlist.getTimesStreamIsContained() > 0);
}
private void onPlaylistSelected(@NonNull final LocalPlaylistManager manager,
@@ -146,9 +147,9 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
@NonNull final List streams) {
final String toastText;
- if (playlist.timesStreamIsContained > 0) {
+ if (playlist.getTimesStreamIsContained() > 0) {
toastText = getString(R.string.playlist_add_stream_success_duplicate,
- playlist.timesStreamIsContained);
+ playlist.getTimesStreamIsContained());
} else {
toastText = getString(R.string.playlist_add_stream_success);
}
@@ -160,8 +161,9 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
.subscribe(ignored -> {
successToast.show();
- if (playlist.thumbnailUrl != null
- && playlist.thumbnailUrl.equals(PlaylistEntity.DEFAULT_THUMBNAIL)) {
+ if (playlist.getThumbnailStreamId() != null
+ && playlist.getThumbnailStreamId() == DEFAULT_THUMBNAIL_ID
+ ) {
playlistDisposables.add(manager
.changePlaylistThumbnail(playlist.getUid(), streams.get(0).getUid(),
false)
diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedDatabaseManager.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedDatabaseManager.kt
index ed65d4048..aacc6757e 100644
--- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedDatabaseManager.kt
+++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedDatabaseManager.kt
@@ -177,7 +177,7 @@ class FeedDatabaseManager(context: Context) {
.observeOn(AndroidSchedulers.mainThread())
}
- fun oldestSubscriptionUpdate(groupId: Long): Flowable> {
+ fun oldestSubscriptionUpdate(groupId: Long): Flowable> {
return when (groupId) {
FeedGroupEntity.GROUP_ALL_ID -> feedTable.oldestSubscriptionUpdateFromAll()
else -> feedTable.oldestSubscriptionUpdate(groupId)
diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt
index 91f98f5d2..bbad7f689 100644
--- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt
+++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedFragment.kt
@@ -507,7 +507,7 @@ class FeedFragment : BaseStateFragment() {
.setTitle(R.string.feed_load_error)
.setPositiveButton(R.string.unsubscribe) { _, _ ->
SubscriptionManager(requireContext())
- .deleteSubscription(subscriptionEntity.serviceId, subscriptionEntity.url)
+ .deleteSubscription(subscriptionEntity.serviceId, subscriptionEntity.url!!)
.subscribe()
handleItemsErrors(nextItemsErrors)
}
diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt
index 728570b17..f916db2b5 100644
--- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt
+++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt
@@ -65,7 +65,7 @@ class FeedViewModel(
feedDatabaseManager.oldestSubscriptionUpdate(groupId),
Function6 { t1: FeedEventManager.Event, t2: Boolean, t3: Boolean, t4: Boolean,
- t5: Long, t6: List ->
+ t5: Long, t6: List ->
return@Function6 CombineResultEventHolder(t1, t2, t3, t4, t5, t6.firstOrNull())
}
)
diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationWorker.kt b/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationWorker.kt
index a40bf35dc..6fe311fb0 100644
--- a/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationWorker.kt
+++ b/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationWorker.kt
@@ -1,6 +1,8 @@
package org.schabi.newpipe.local.feed.notifications
import android.content.Context
+import android.content.pm.ServiceInfo
+import android.os.Build
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.work.Constraints
@@ -83,7 +85,9 @@ class NotificationWorker(
.setPriority(NotificationCompat.PRIORITY_LOW)
.setContentTitle(applicationContext.getString(R.string.feed_notification_loading))
.build()
- setForegroundAsync(ForegroundInfo(FeedLoadService.NOTIFICATION_ID, notification))
+ // ServiceInfo constants are not used below Android Q, so 0 is set here
+ val serviceType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC else 0
+ setForegroundAsync(ForegroundInfo(FeedLoadService.NOTIFICATION_ID, notification, serviceType))
}
companion object {
diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt b/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt
index f960040de..4aa825ca8 100644
--- a/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt
+++ b/app/src/main/java/org/schabi/newpipe/local/feed/service/FeedLoadService.kt
@@ -31,6 +31,7 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.PendingIntentCompat
import androidx.core.app.ServiceCompat
+import androidx.core.content.ContextCompat
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.disposables.Disposable
@@ -200,7 +201,7 @@ class FeedLoadService : Service() {
}
}
}
- registerReceiver(broadcastReceiver, IntentFilter(ACTION_CANCEL))
+ ContextCompat.registerReceiver(this, broadcastReceiver, IntentFilter(ACTION_CANCEL), ContextCompat.RECEIVER_NOT_EXPORTED)
}
// /////////////////////////////////////////////////////////////////////////
diff --git a/app/src/main/java/org/schabi/newpipe/local/holder/LocalPlaylistItemHolder.java b/app/src/main/java/org/schabi/newpipe/local/holder/LocalPlaylistItemHolder.java
index 336f5cfe3..528275d75 100644
--- a/app/src/main/java/org/schabi/newpipe/local/holder/LocalPlaylistItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/local/holder/LocalPlaylistItemHolder.java
@@ -35,15 +35,15 @@ public class LocalPlaylistItemHolder extends PlaylistItemHolder {
}
final PlaylistMetadataEntry item = (PlaylistMetadataEntry) localItem;
- itemTitleView.setText(item.name);
+ itemTitleView.setText(item.getOrderingName());
itemStreamCountView.setText(Localization.localizeStreamCountMini(
- itemStreamCountView.getContext(), item.streamCount));
+ itemStreamCountView.getContext(), item.getStreamCount()));
itemUploaderView.setVisibility(View.INVISIBLE);
- PicassoHelper.loadPlaylistThumbnail(item.thumbnailUrl).into(itemThumbnailView);
+ PicassoHelper.loadPlaylistThumbnail(item.getThumbnailUrl()).into(itemThumbnailView);
if (item instanceof PlaylistDuplicatesEntry
- && ((PlaylistDuplicatesEntry) item).timesStreamIsContained > 0) {
+ && ((PlaylistDuplicatesEntry) item).getTimesStreamIsContained() > 0) {
itemView.setAlpha(GRAYED_OUT_ALPHA);
} else {
itemView.setAlpha(1.0f);
diff --git a/app/src/main/java/org/schabi/newpipe/local/holder/RemotePlaylistItemHolder.java b/app/src/main/java/org/schabi/newpipe/local/holder/RemotePlaylistItemHolder.java
index 765732063..3a339aec8 100644
--- a/app/src/main/java/org/schabi/newpipe/local/holder/RemotePlaylistItemHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/local/holder/RemotePlaylistItemHolder.java
@@ -34,7 +34,7 @@ public class RemotePlaylistItemHolder extends PlaylistItemHolder {
}
final PlaylistRemoteEntity item = (PlaylistRemoteEntity) localItem;
- itemTitleView.setText(item.getName());
+ itemTitleView.setText(item.getOrderingName());
itemStreamCountView.setText(Localization.localizeStreamCountMini(
itemStreamCountView.getContext(), item.getStreamCount()));
// Here is where the uploader name is set in the bookmarked playlists library
diff --git a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java
index f5562549c..1efc0a84c 100644
--- a/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistFragment.java
@@ -111,7 +111,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment() {
@Override
public void selected(final LocalItem selectedItem) {
- if (selectedItem instanceof PlaylistStreamEntry) {
- final StreamEntity item =
- ((PlaylistStreamEntry) selectedItem).getStreamEntity();
+ if (selectedItem instanceof PlaylistStreamEntry entry) {
+ final StreamEntity item = entry.getStreamEntity();
NavigationHelper.openVideoDetailFragment(requireContext(), getFM(),
item.getServiceId(), item.getUrl(), item.getTitle(), null, false);
}
@@ -496,6 +495,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment items = itemListAdapter.getItemsList();
final List streamIds = new ArrayList<>(items.size());
for (final LocalItem item : items) {
- if (item instanceof PlaylistStreamEntry) {
- streamIds.add(((PlaylistStreamEntry) item).getStreamId());
+ if (item instanceof PlaylistStreamEntry entry) {
+ streamIds.add(entry.getStreamId());
}
}
@@ -767,6 +768,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment {
- if (resultServiceIntent != null && getContext() != null) {
- getContext().startService(resultServiceIntent);
- }
+ requireContext().startService(resultServiceIntent);
dismiss();
})
.create();
@@ -50,11 +45,7 @@ public class ImportConfirmationDialog extends DialogFragment {
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (resultServiceIntent == null) {
- throw new IllegalStateException("Result intent is null");
- }
-
- Bridge.restoreInstanceState(this, savedInstanceState);
+ resultServiceIntent = requireArguments().getParcelable(EXTRA_RESULT_SERVICE_INTENT);
}
@Override
diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionManager.kt b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionManager.kt
index 474add4f4..c0783e812 100644
--- a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionManager.kt
+++ b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionManager.kt
@@ -26,7 +26,7 @@ class SubscriptionManager(context: Context) {
private val feedDatabaseManager = FeedDatabaseManager(context)
fun subscriptionTable(): SubscriptionDAO = subscriptionTable
- fun subscriptions() = subscriptionTable.all
+ fun subscriptions() = subscriptionTable.getAll()
fun getSubscriptions(
currentGroupId: Long = FeedGroupEntity.GROUP_ALL_ID,
@@ -44,7 +44,7 @@ class SubscriptionManager(context: Context) {
}
}
showOnlyUngrouped -> subscriptionTable.getSubscriptionsOnlyUngrouped(currentGroupId)
- else -> subscriptionTable.all
+ else -> subscriptionTable.getAll()
}
}
@@ -71,12 +71,12 @@ class SubscriptionManager(context: Context) {
subscriptionTable.getSubscription(info.serviceId, info.url)
.flatMapCompletable {
Completable.fromRunnable {
- it.setData(
- info.name,
- ImageStrategy.imageListToDbUrl(info.avatars),
- info.description,
- info.subscriberCount
- )
+ it.apply {
+ name = info.name
+ avatarUrl = ImageStrategy.imageListToDbUrl(info.avatars)
+ description = info.description
+ subscriberCount = info.subscriberCount
+ }
subscriptionTable.update(it)
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java
index 77a70afa9..16a8990a6 100644
--- a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionsImportFragment.java
@@ -89,8 +89,8 @@ public class SubscriptionsImportFragment extends BaseFragment {
if (supportedSources.isEmpty() && currentServiceId != Constants.NO_SERVICE_ID) {
ErrorUtil.showSnackbar(activity,
new ErrorInfo(new String[]{}, UserAction.SUBSCRIPTION_IMPORT_EXPORT,
- ServiceHelper.getNameOfServiceById(currentServiceId),
"Service does not support importing subscriptions",
+ currentServiceId,
R.string.general_error));
activity.finish();
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java
index 98da962e7..42f6cbf36 100644
--- a/app/src/main/java/org/schabi/newpipe/player/Player.java
+++ b/app/src/main/java/org/schabi/newpipe/player/Player.java
@@ -24,12 +24,12 @@ import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK_ADJ
import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SKIP;
import static com.google.android.exoplayer2.Player.DiscontinuityReason;
import static com.google.android.exoplayer2.Player.Listener;
+import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_OFF;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ONE;
import static com.google.android.exoplayer2.Player.RepeatMode;
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
-import static org.schabi.newpipe.player.helper.PlayerHelper.nextRepeatMode;
import static org.schabi.newpipe.player.helper.PlayerHelper.retrievePlaybackParametersFromPrefs;
import static org.schabi.newpipe.player.helper.PlayerHelper.retrieveSeekDurationFromPreferences;
import static org.schabi.newpipe.player.helper.PlayerHelper.savePlaybackParametersToPrefs;
@@ -60,6 +60,8 @@ import android.view.LayoutInflater;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+import androidx.core.content.IntentCompat;
import androidx.core.math.MathUtils;
import androidx.preference.PreferenceManager;
@@ -108,6 +110,7 @@ import org.schabi.newpipe.player.playback.MediaSourceManager;
import org.schabi.newpipe.player.playback.PlaybackListener;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
+import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.player.resolver.AudioPlaybackResolver;
import org.schabi.newpipe.player.resolver.VideoPlaybackResolver;
import org.schabi.newpipe.player.resolver.VideoPlaybackResolver.SourceType;
@@ -117,6 +120,7 @@ import org.schabi.newpipe.player.ui.PlayerUiList;
import org.schabi.newpipe.player.ui.PopupPlayerUi;
import org.schabi.newpipe.player.ui.VideoPlayerUi;
import org.schabi.newpipe.util.DependentPreferenceHelper;
+import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.ListHelper;
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.SerializedCache;
@@ -124,14 +128,17 @@ import org.schabi.newpipe.util.StreamTypeUtil;
import org.schabi.newpipe.util.image.PicassoHelper;
import java.util.List;
+import java.util.Objects;
import java.util.Optional;
import java.util.stream.IntStream;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
+import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.disposables.SerialDisposable;
+import io.reactivex.rxjava3.schedulers.Schedulers;
public final class Player implements PlaybackListener, Listener {
public static final boolean DEBUG = MainActivity.DEBUG;
@@ -153,15 +160,13 @@ public final class Player implements PlaybackListener, Listener {
// Intent
//////////////////////////////////////////////////////////////////////////*/
- public static final String REPEAT_MODE = "repeat_mode";
public static final String PLAYBACK_QUALITY = "playback_quality";
public static final String PLAY_QUEUE_KEY = "play_queue_key";
- public static final String ENQUEUE = "enqueue";
- public static final String ENQUEUE_NEXT = "enqueue_next";
public static final String RESUME_PLAYBACK = "resume_playback";
public static final String PLAY_WHEN_READY = "play_when_ready";
public static final String PLAYER_TYPE = "player_type";
- public static final String IS_MUTED = "is_muted";
+ public static final String PLAYER_INTENT_TYPE = "player_intent_type";
+ public static final String PLAYER_INTENT_DATA = "player_intent_data";
/*//////////////////////////////////////////////////////////////////////////
// Time constants
@@ -246,6 +251,8 @@ public final class Player implements PlaybackListener, Listener {
private final SerialDisposable progressUpdateDisposable = new SerialDisposable();
@NonNull
private final CompositeDisposable databaseUpdateDisposable = new CompositeDisposable();
+ @NonNull
+ private final CompositeDisposable streamItemDisposable = new CompositeDisposable();
// This is the only listener we need for thumbnail loading, since there is always at most only
// one thumbnail being loaded at a time. This field is also here to maintain a strong reference,
@@ -346,49 +353,121 @@ public final class Player implements PlaybackListener, Listener {
@SuppressWarnings("MethodLength")
public void handleIntent(@NonNull final Intent intent) {
- // fail fast if no play queue was provided
- final String queueCache = intent.getStringExtra(PLAY_QUEUE_KEY);
- if (queueCache == null) {
+ final var playerIntentType = IntentCompat.getSerializableExtra(intent, PLAYER_INTENT_TYPE,
+ PlayerIntentType.class);
+ if (playerIntentType == null) {
return;
}
- final PlayQueue newQueue = SerializedCache.getInstance().take(queueCache, PlayQueue.class);
- if (newQueue == null) {
- return;
+ // TODO: this should be in the second switch below, but I’m not sure whether I
+ // can move the initUIs stuff without breaking the setup for edge cases somehow.
+ // when playing from a timestamp, keep the current player as-is.
+ if (playerIntentType != PlayerIntentType.TimestampChange) {
+ playerType = IntentCompat.getSerializableExtra(intent, PLAYER_TYPE, PlayerType.class);
}
-
- final PlayerType oldPlayerType = playerType;
- playerType = PlayerType.retrieveFromIntent(intent);
initUIsForCurrentPlayerType();
- // We need to setup audioOnly before super(), see "sourceOf"
isAudioOnly = audioPlayerSelected();
if (intent.hasExtra(PLAYBACK_QUALITY)) {
videoResolver.setPlaybackQuality(intent.getStringExtra(PLAYBACK_QUALITY));
}
- // Resolve enqueue intents
- if (intent.getBooleanExtra(ENQUEUE, false) && playQueue != null) {
- playQueue.append(newQueue.getStreams());
- return;
+ final boolean playWhenReady = intent.getBooleanExtra(PLAY_WHEN_READY, true);
- // Resolve enqueue next intents
- } else if (intent.getBooleanExtra(ENQUEUE_NEXT, false) && playQueue != null) {
- final int currentIndex = playQueue.getIndex();
- playQueue.append(newQueue.getStreams());
- playQueue.move(playQueue.size() - 1, currentIndex + 1);
+ switch (playerIntentType) {
+ case Enqueue -> {
+ if (playQueue != null) {
+ final PlayQueue newQueue = getPlayQueueFromCache(intent);
+ if (newQueue == null) {
+ return;
+ }
+ playQueue.append(newQueue.getStreams());
+ return;
+ }
+
+ // TODO: This falls through to the old logic, there was no playQueue
+ // yet so we should start the player and add the new video
+ break;
+ }
+ case EnqueueNext -> {
+ if (playQueue != null) {
+ final PlayQueue newQueue = getPlayQueueFromCache(intent);
+ if (newQueue == null) {
+ return;
+ }
+ final PlayQueueItem newItem = newQueue.getStreams().get(0);
+ playQueue.enqueueNext(newItem, false);
+ return;
+ }
+
+ // TODO: This falls through to the old logic, there was no playQueue
+ // yet so we should start the player and add the new video
+ break;
+ }
+ case TimestampChange -> {
+ final var data = Objects.requireNonNull(IntentCompat.getParcelableExtra(intent,
+ PLAYER_INTENT_DATA, TimestampChangeData.class));
+ final Single single =
+ ExtractorHelper.getStreamInfo(data.getServiceId(), data.getUrl(), false);
+ streamItemDisposable.add(single.subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(info -> {
+ final @Nullable PlayQueue oldPlayQueue = playQueue;
+ info.setStartPosition(data.getSeconds());
+ final PlayQueueItem playQueueItem = new PlayQueueItem(info);
+
+ // If the stream is already playing,
+ // we can just seek to the appropriate timestamp
+ if (oldPlayQueue != null
+ && playQueueItem.isSameItem(oldPlayQueue.getItem())) {
+ // Player can have state = IDLE when playback is stopped or failed
+ // and we should retry in this case
+ if (simpleExoPlayer.getPlaybackState()
+ == com.google.android.exoplayer2.Player.STATE_IDLE) {
+ simpleExoPlayer.prepare();
+ }
+ simpleExoPlayer.seekTo(oldPlayQueue.getIndex(),
+ data.getSeconds() * 1000L);
+ simpleExoPlayer.setPlayWhenReady(playWhenReady);
+
+ } else {
+ final PlayQueue newPlayQueue;
+
+ // If there is no queue yet, just add our item
+ if (oldPlayQueue == null) {
+ newPlayQueue = new SinglePlayQueue(playQueueItem);
+
+ // else we add the timestamped stream behind the current video
+ // and start playing it.
+ } else {
+ oldPlayQueue.enqueueNext(playQueueItem, true);
+ oldPlayQueue.offsetIndex(1);
+ newPlayQueue = oldPlayQueue;
+ }
+ initPlayback(newPlayQueue, playWhenReady);
+ }
+
+ }, throwable -> {
+ // This will only show a snackbar if the passed context has a root view:
+ // otherwise it will resort to showing a notification, so we are safe
+ // here.
+ final var info = new ErrorInfo(throwable, UserAction.PLAY_ON_POPUP,
+ data.getUrl(), null, data.getUrl());
+ ErrorUtil.createNotification(context, info);
+ }));
+ return;
+ }
+ case AllOthers -> {
+ // fallthrough; TODO: put other intent data in separate cases
+ }
+ }
+
+ final PlayQueue newQueue = getPlayQueueFromCache(intent);
+ if (newQueue == null) {
return;
}
- final PlaybackParameters savedParameters = retrievePlaybackParametersFromPrefs(this);
- final float playbackSpeed = savedParameters.speed;
- final float playbackPitch = savedParameters.pitch;
- final boolean playbackSkipSilence = getPrefs().getBoolean(getContext().getString(
- R.string.playback_skip_silence_key), getPlaybackSkipSilence());
-
+ // branching parameters for below
final boolean samePlayQueue = playQueue != null && playQueue.equalStreamsAndIndex(newQueue);
- final int repeatMode = intent.getIntExtra(REPEAT_MODE, getRepeatMode());
- final boolean playWhenReady = intent.getBooleanExtra(PLAY_WHEN_READY, true);
- final boolean isMuted = intent.getBooleanExtra(IS_MUTED, isMuted());
/*
* TODO As seen in #7427 this does not work:
@@ -403,7 +482,7 @@ public final class Player implements PlaybackListener, Listener {
if (!exoPlayerIsNull()
&& newQueue.size() == 1 && newQueue.getItem() != null
&& playQueue != null && playQueue.size() == 1 && playQueue.getItem() != null
- && newQueue.getItem().getUrl().equals(playQueue.getItem().getUrl())
+ && newQueue.getItem().isSameItem(playQueue.getItem())
&& newQueue.getItem().getRecoveryPosition() != PlayQueueItem.RECOVERY_UNSET) {
// Player can have state = IDLE when playback is stopped or failed
// and we should retry in this case
@@ -429,7 +508,8 @@ public final class Player implements PlaybackListener, Listener {
} else if (intent.getBooleanExtra(RESUME_PLAYBACK, false)
&& DependentPreferenceHelper.getResumePlaybackEnabled(context)
- && !samePlayQueue
+ // !samePlayQueue
+ && (playQueue == null || !playQueue.equalStreamsAndIndex(newQueue))
&& !newQueue.isEmpty()
&& newQueue.getItem() != null
&& newQueue.getItem().getRecoveryPosition() == PlayQueueItem.RECOVERY_UNSET) {
@@ -445,30 +525,30 @@ public final class Player implements PlaybackListener, Listener {
newQueue.setRecovery(newQueue.getIndex(),
state.getProgressMillis());
}
- initPlayback(newQueue, repeatMode, playbackSpeed, playbackPitch,
- playbackSkipSilence, playWhenReady, isMuted);
+ initPlayback(newQueue, playWhenReady);
},
error -> {
if (DEBUG) {
Log.w(TAG, "Failed to start playback", error);
}
// In case any error we can start playback without history
- initPlayback(newQueue, repeatMode, playbackSpeed, playbackPitch,
- playbackSkipSilence, playWhenReady, isMuted);
+ initPlayback(newQueue, playWhenReady);
},
() -> {
// Completed but not found in history
- initPlayback(newQueue, repeatMode, playbackSpeed, playbackPitch,
- playbackSkipSilence, playWhenReady, isMuted);
+ initPlayback(newQueue, playWhenReady);
}
));
} else {
// Good to go...
// In a case of equal PlayQueues we can re-init old one but only when it is disposed
- initPlayback(samePlayQueue ? playQueue : newQueue, repeatMode, playbackSpeed,
- playbackPitch, playbackSkipSilence, playWhenReady, isMuted);
+ initPlayback(samePlayQueue ? playQueue : newQueue, playWhenReady);
}
+ }
+
+
+ public void handleIntentPost(final PlayerType oldPlayerType) {
if (oldPlayerType != playerType && playQueue != null) {
// If playerType changes from one to another we should reload the player
// (to disable/enable video stream or to set quality)
@@ -479,6 +559,19 @@ public final class Player implements PlaybackListener, Listener {
NavigationHelper.sendPlayerStartedEvent(context);
}
+ @Nullable
+ private static PlayQueue getPlayQueueFromCache(@NonNull final Intent intent) {
+ final String queueCache = intent.getStringExtra(PLAY_QUEUE_KEY);
+ if (queueCache == null) {
+ return null;
+ }
+ final PlayQueue newQueue = SerializedCache.getInstance().take(queueCache, PlayQueue.class);
+ if (newQueue == null) {
+ return null;
+ }
+ return newQueue;
+ }
+
private void initUIsForCurrentPlayerType() {
if ((UIs.get(MainPlayerUi.class).isPresent() && playerType == PlayerType.MAIN)
|| (UIs.get(PopupPlayerUi.class).isPresent() && playerType == PlayerType.POPUP)) {
@@ -512,16 +605,13 @@ public final class Player implements PlaybackListener, Listener {
}
private void initPlayback(@NonNull final PlayQueue queue,
- @RepeatMode final int repeatMode,
- final float playbackSpeed,
- final float playbackPitch,
- final boolean playbackSkipSilence,
- final boolean playOnReady,
- final boolean isMuted) {
+ final boolean playOnReady) {
destroyPlayer();
initPlayer(playOnReady);
- setRepeatMode(repeatMode);
- setPlaybackParameters(playbackSpeed, playbackPitch, playbackSkipSilence);
+ final boolean playbackSkipSilence = getPrefs().getBoolean(getContext().getString(
+ R.string.playback_skip_silence_key), getPlaybackSkipSilence());
+ final PlaybackParameters savedParameters = retrievePlaybackParametersFromPrefs(this);
+ setPlaybackParameters(savedParameters.speed, savedParameters.pitch, playbackSkipSilence);
playQueue = queue;
playQueue.init();
@@ -529,7 +619,7 @@ public final class Player implements PlaybackListener, Listener {
UIs.call(PlayerUi::initPlayback);
- simpleExoPlayer.setVolume(isMuted ? 0 : 1);
+ simpleExoPlayer.setVolume(isMuted() ? 0 : 1);
notifyQueueUpdateToListeners();
}
@@ -611,6 +701,7 @@ public final class Player implements PlaybackListener, Listener {
databaseUpdateDisposable.clear();
progressUpdateDisposable.set(null);
+ streamItemDisposable.clear();
cancelLoadingCurrentThumbnail();
UIs.destroyAll(Object.class); // destroy every UI: obviously every UI extends Object
@@ -764,7 +855,8 @@ public final class Player implements PlaybackListener, Listener {
private void registerBroadcastReceiver() {
// Try to unregister current first
unregisterBroadcastReceiver();
- context.registerReceiver(broadcastReceiver, intentFilter);
+ ContextCompat.registerReceiver(context, broadcastReceiver, intentFilter,
+ ContextCompat.RECEIVER_EXPORTED);
}
private void unregisterBroadcastReceiver() {
@@ -1176,16 +1268,25 @@ public final class Player implements PlaybackListener, Listener {
return exoPlayerIsNull() ? REPEAT_MODE_OFF : simpleExoPlayer.getRepeatMode();
}
- public void setRepeatMode(@RepeatMode final int repeatMode) {
+ public void cycleNextRepeatMode() {
if (!exoPlayerIsNull()) {
+ @RepeatMode final int repeatMode;
+ switch (simpleExoPlayer.getRepeatMode()) {
+ case REPEAT_MODE_OFF:
+ repeatMode = REPEAT_MODE_ONE;
+ break;
+ case REPEAT_MODE_ONE:
+ repeatMode = REPEAT_MODE_ALL;
+ break;
+ case REPEAT_MODE_ALL:
+ default:
+ repeatMode = REPEAT_MODE_OFF;
+ break;
+ }
simpleExoPlayer.setRepeatMode(repeatMode);
}
}
- public void cycleNextRepeatMode() {
- setRepeatMode(nextRepeatMode(getRepeatMode()));
- }
-
@Override
public void onRepeatModeChanged(@RepeatMode final int repeatMode) {
if (DEBUG) {
@@ -1288,7 +1389,8 @@ public final class Player implements PlaybackListener, Listener {
UserAction.PLAY_STREAM,
"Loading failed for [" + currentMetadata.getTitle()
+ "]: " + currentMetadata.getStreamUrl(),
- currentMetadata.getServiceId());
+ currentMetadata.getServiceId(),
+ currentMetadata.getStreamUrl());
ErrorUtil.createNotification(context, errorInfo);
}
@@ -1504,7 +1606,7 @@ public final class Player implements PlaybackListener, Listener {
errorInfo = new ErrorInfo(error, UserAction.PLAY_STREAM,
"Player error[type=" + error.getErrorCodeName()
+ "] occurred while playing " + currentMetadata.getStreamUrl(),
- currentMetadata.getServiceId());
+ currentMetadata.getServiceId(), currentMetadata.getStreamUrl());
}
ErrorUtil.createNotification(context, errorInfo);
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayerIntentType.kt b/app/src/main/java/org/schabi/newpipe/player/PlayerIntentType.kt
new file mode 100644
index 000000000..ed0c19c99
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/player/PlayerIntentType.kt
@@ -0,0 +1,24 @@
+package org.schabi.newpipe.player
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+// We model this as an enum class plus one struct for each enum value
+// so we can consume it from Java properly. After converting to Kotlin,
+// we could switch to a sealed enum class & a proper Kotlin `when` match.
+enum class PlayerIntentType {
+ Enqueue,
+ EnqueueNext,
+ TimestampChange,
+ AllOthers
+}
+
+/**
+ * A timestamp on the given was clicked and we should switch the playing stream to it.
+ */
+@Parcelize
+data class TimestampChangeData(
+ val serviceId: Int,
+ val url: String,
+ val seconds: Int
+) : Parcelable
diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayerService.java b/app/src/main/java/org/schabi/newpipe/player/PlayerService.java
index adc050e4b..dba30f9e8 100644
--- a/app/src/main/java/org/schabi/newpipe/player/PlayerService.java
+++ b/app/src/main/java/org/schabi/newpipe/player/PlayerService.java
@@ -40,6 +40,7 @@ import org.schabi.newpipe.player.mediabrowser.MediaBrowserImpl;
import org.schabi.newpipe.player.mediabrowser.MediaBrowserPlaybackPreparer;
import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi;
import org.schabi.newpipe.player.notification.NotificationPlayerUi;
+import org.schabi.newpipe.player.notification.NotificationUtil;
import org.schabi.newpipe.util.ThemeHelper;
import java.lang.ref.WeakReference;
@@ -156,23 +157,24 @@ public final class PlayerService extends MediaBrowserServiceCompat {
}
}
- if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
- && (player == null || player.getPlayQueue() == null)) {
- /*
- No need to process media button's actions if the player is not working, otherwise
- the player service would strangely start with nothing to play
- Stop the service in this case, which will be removed from the foreground and its
- notification cancelled in its destruction
- */
+ if (player == null) {
+ // No need to process media button's actions or other system intents if the player is
+ // not running. However, since the current intent might have been issued by the system
+ // with `startForegroundService()` (for unknown reasons), we need to ensure that we post
+ // a (dummy) foreground notification, otherwise we'd incur in
+ // "Context.startForegroundService() did not then call Service.startForeground()". Then
+ // we stop the service again.
+ Log.d(TAG, "onStartCommand() got a useless intent, closing the service");
+ NotificationUtil.startForegroundWithDummyNotification(this);
destroyPlayerAndStopService();
return START_NOT_STICKY;
}
- if (player != null) {
- player.handleIntent(intent);
- player.UIs().get(MediaSessionPlayerUi.class)
- .ifPresent(ui -> ui.handleMediaButtonIntent(intent));
- }
+ final PlayerType oldPlayerType = player.getPlayerType();
+ player.handleIntent(intent);
+ player.handleIntentPost(oldPlayerType);
+ player.UIs().get(MediaSessionPlayerUi.class)
+ .ifPresent(ui -> ui.handleMediaButtonIntent(intent));
return START_NOT_STICKY;
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/PlayerType.java b/app/src/main/java/org/schabi/newpipe/player/PlayerType.java
index 171a70395..f74389d79 100644
--- a/app/src/main/java/org/schabi/newpipe/player/PlayerType.java
+++ b/app/src/main/java/org/schabi/newpipe/player/PlayerType.java
@@ -1,32 +1,7 @@
package org.schabi.newpipe.player;
-import static org.schabi.newpipe.player.Player.PLAYER_TYPE;
-
-import android.content.Intent;
-
public enum PlayerType {
MAIN,
AUDIO,
POPUP;
-
- /**
- * @return an integer representing this {@link PlayerType}, to be used to save it in intents
- * @see #retrieveFromIntent(Intent) Use retrieveFromIntent() to retrieve and convert player type
- * integers from an intent
- */
- public int valueForIntent() {
- return ordinal();
- }
-
- /**
- * @param intent the intent to retrieve a player type from
- * @return the player type integer retrieved from the intent, converted back into a {@link
- * PlayerType}, or {@link PlayerType#MAIN} if there is no player type extra in the
- * intent
- * @throws ArrayIndexOutOfBoundsException if the intent contains an invalid player type integer
- * @see #valueForIntent() Use valueForIntent() to obtain valid player type integers
- */
- public static PlayerType retrieveFromIntent(final Intent intent) {
- return values()[intent.getIntExtra(PLAYER_TYPE, MAIN.valueForIntent())];
- }
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java b/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java
index a05990816..084336d54 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/AudioReactor.java
@@ -154,9 +154,6 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, An
notifyAudioSessionUpdate(true, audioSessionId);
}
private void notifyAudioSessionUpdate(final boolean active, final int audioSessionId) {
- if (!PlayerHelper.isUsingDSP()) {
- return;
- }
final Intent intent = new Intent(active
? AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION
: AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
index 266d65f36..0f9579352 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java
@@ -1,8 +1,5 @@
package org.schabi.newpipe.player.helper;
-import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL;
-import static com.google.android.exoplayer2.Player.REPEAT_MODE_OFF;
-import static com.google.android.exoplayer2.Player.REPEAT_MODE_ONE;
import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_ALWAYS;
import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER;
import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI;
@@ -25,7 +22,6 @@ import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import com.google.android.exoplayer2.PlaybackParameters;
-import com.google.android.exoplayer2.Player.RepeatMode;
import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
@@ -145,11 +141,11 @@ public final class PlayerHelper {
@ResizeMode final int resizeMode) {
switch (resizeMode) {
case AspectRatioFrameLayout.RESIZE_MODE_FIT:
- return context.getResources().getString(R.string.resize_fit);
+ return context.getString(R.string.resize_fit);
case AspectRatioFrameLayout.RESIZE_MODE_FILL:
- return context.getResources().getString(R.string.resize_fill);
+ return context.getString(R.string.resize_fill);
case AspectRatioFrameLayout.RESIZE_MODE_ZOOM:
- return context.getResources().getString(R.string.resize_zoom);
+ return context.getString(R.string.resize_zoom);
case AspectRatioFrameLayout.RESIZE_MODE_FIXED_HEIGHT:
case AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH:
default:
@@ -300,10 +296,6 @@ public final class PlayerHelper {
AdaptiveTrackSelection.DEFAULT_BANDWIDTH_FRACTION);
}
- public static boolean isUsingDSP() {
- return true;
- }
-
@NonNull
public static CaptionStyleCompat getCaptionStyle(@NonNull final Context context) {
final CaptioningManager captioningManager = ContextCompat.getSystemService(context,
@@ -410,23 +402,9 @@ public final class PlayerHelper {
return singlePlayQueue;
}
-
// endregion
// region Utils used by player
- @RepeatMode
- public static int nextRepeatMode(@RepeatMode final int repeatMode) {
- switch (repeatMode) {
- case REPEAT_MODE_OFF:
- return REPEAT_MODE_ONE;
- case REPEAT_MODE_ONE:
- return REPEAT_MODE_ALL;
- case REPEAT_MODE_ALL:
- default:
- return REPEAT_MODE_OFF;
- }
- }
-
@ResizeMode
public static int retrieveResizeModeFromPrefs(final Player player) {
return player.getPrefs().getInt(player.getContext().getString(R.string.last_resize_mode),
diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java
index 97f2d6717..9edfc804a 100644
--- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java
+++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java
@@ -192,9 +192,11 @@ public final class PlayerHolder {
startPlayerListener();
// ^ will call listener.onPlayerConnected() down the line if there is an active player
- // notify the main activity that binding the service has completed, so that it can
- // open the bottom mini-player
- NavigationHelper.sendPlayerStartedEvent(localBinder.getService());
+ if (playerService != null && playerService.getPlayer() != null) {
+ // notify the main activity that binding the service has completed and that there is
+ // a player, so that it can open the bottom mini-player
+ NavigationHelper.sendPlayerStartedEvent(localBinder.getService());
+ }
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/mediabrowser/MediaBrowserImpl.kt b/app/src/main/java/org/schabi/newpipe/player/mediabrowser/MediaBrowserImpl.kt
index b7d57657d..d221d704b 100644
--- a/app/src/main/java/org/schabi/newpipe/player/mediabrowser/MediaBrowserImpl.kt
+++ b/app/src/main/java/org/schabi/newpipe/player/mediabrowser/MediaBrowserImpl.kt
@@ -315,7 +315,7 @@ class MediaBrowserImpl(
}
private fun populateHistory(): Single> {
- val history = database.streamHistoryDAO().getHistory().firstOrError()
+ val history = database.streamHistoryDAO().history.firstOrError()
return history.map { items ->
items.map { this.createHistoryMediaItem(it) }
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/mediabrowser/MediaBrowserPlaybackPreparer.kt b/app/src/main/java/org/schabi/newpipe/player/mediabrowser/MediaBrowserPlaybackPreparer.kt
index 2948eeaf8..072a8f332 100644
--- a/app/src/main/java/org/schabi/newpipe/player/mediabrowser/MediaBrowserPlaybackPreparer.kt
+++ b/app/src/main/java/org/schabi/newpipe/player/mediabrowser/MediaBrowserPlaybackPreparer.kt
@@ -17,6 +17,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import org.schabi.newpipe.MainActivity
import org.schabi.newpipe.NewPipeDatabase
import org.schabi.newpipe.R
+import org.schabi.newpipe.error.ErrorInfo
import org.schabi.newpipe.extractor.InfoItem.InfoType
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler
@@ -84,7 +85,7 @@ class MediaBrowserPlaybackPreparer(
},
{ throwable ->
Log.e(TAG, "Failed to start playback of media ID [$mediaId]", throwable)
- onPrepareError()
+ onPrepareError(throwable)
}
)
}
@@ -115,9 +116,9 @@ class MediaBrowserPlaybackPreparer(
)
}
- private fun onPrepareError() {
+ private fun onPrepareError(throwable: Throwable) {
setMediaSessionError.accept(
- ContextCompat.getString(context, R.string.error_snackbar_message),
+ ErrorInfo.getMessage(throwable, null, null).getString(context),
PlaybackStateCompat.ERROR_CODE_APP_ERROR
)
}
@@ -214,7 +215,7 @@ class MediaBrowserPlaybackPreparer(
}
val streamId = path[0].toLong()
- return database.streamHistoryDAO().getHistory()
+ return database.streamHistoryDAO().history
.firstOrError()
.map { items ->
val infoItems = items
diff --git a/app/src/main/java/org/schabi/newpipe/player/mediabrowser/PackageValidator.kt b/app/src/main/java/org/schabi/newpipe/player/mediabrowser/PackageValidator.kt
index 973b11b37..05719b6d4 100644
--- a/app/src/main/java/org/schabi/newpipe/player/mediabrowser/PackageValidator.kt
+++ b/app/src/main/java/org/schabi/newpipe/player/mediabrowser/PackageValidator.kt
@@ -147,18 +147,15 @@ internal class PackageValidator(context: Context) {
private fun buildCallerInfo(callingPackage: String): CallerPackageInfo? {
val packageInfo = getPackageInfo(callingPackage) ?: return null
- val appName = packageInfo.applicationInfo.loadLabel(packageManager).toString()
- val uid = packageInfo.applicationInfo.uid
+ val appName = packageInfo.applicationInfo?.loadLabel(packageManager).toString()
+ val uid = packageInfo.applicationInfo?.uid ?: -1
val signature = getSignature(packageInfo)
- val requestedPermissions = packageInfo.requestedPermissions
- val permissionFlags = packageInfo.requestedPermissionsFlags
- val activePermissions = mutableSetOf()
- requestedPermissions?.forEachIndexed { index, permission ->
- if (permissionFlags[index] and REQUESTED_PERMISSION_GRANTED != 0) {
- activePermissions += permission
- }
- }
+ val requestedPermissions = packageInfo.requestedPermissions?.asSequence().orEmpty()
+ val permissionFlags = packageInfo.requestedPermissionsFlags?.asSequence().orEmpty()
+ val activePermissions = (requestedPermissions zip permissionFlags)
+ .filter { (permission, flag) -> flag and REQUESTED_PERMISSION_GRANTED != 0 }
+ .mapTo(mutableSetOf()) { (permission, flag) -> permission }
return CallerPackageInfo(appName, callingPackage, uid, signature, activePermissions.toSet())
}
@@ -189,12 +186,12 @@ internal class PackageValidator(context: Context) {
*/
@Suppress("deprecation")
private fun getSignature(packageInfo: PackageInfo): String? =
- if (packageInfo.signatures == null || packageInfo.signatures.size != 1) {
+ if (packageInfo.signatures == null || packageInfo.signatures!!.size != 1) {
// Security best practices dictate that an app should be signed with exactly one (1)
// signature. Because of this, if there are multiple signatures, reject it.
null
} else {
- val certificate = packageInfo.signatures[0].toByteArray()
+ val certificate = packageInfo.signatures!![0].toByteArray()
getSignatureSha256(certificate)
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java b/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java
index 30420b0c7..9b9c47b0e 100644
--- a/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java
+++ b/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java
@@ -5,7 +5,9 @@ import static androidx.media.app.NotificationCompat.MediaStyle;
import static org.schabi.newpipe.player.notification.NotificationConstants.ACTION_CLOSE;
import android.annotation.SuppressLint;
+import android.app.Notification;
import android.app.PendingIntent;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.ServiceInfo;
import android.graphics.Bitmap;
@@ -23,6 +25,8 @@ import androidx.core.content.ContextCompat;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.player.Player;
+import org.schabi.newpipe.player.PlayerIntentType;
+import org.schabi.newpipe.player.PlayerService;
import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi;
import org.schabi.newpipe.util.NavigationHelper;
@@ -89,12 +93,9 @@ public final class NotificationUtil {
Log.d(TAG, "createNotification()");
}
notificationManager = NotificationManagerCompat.from(player.getContext());
- final NotificationCompat.Builder builder =
- new NotificationCompat.Builder(player.getContext(),
- player.getContext().getString(R.string.notification_channel_id));
- final MediaStyle mediaStyle = new MediaStyle();
// setup media style (compact notification slots and media session)
+ final MediaStyle mediaStyle = new MediaStyle();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
// notification actions are ignored on Android 13+, and are replaced by code in
// MediaSessionPlayerUi
@@ -107,18 +108,9 @@ public final class NotificationUtil {
.ifPresent(mediaStyle::setMediaSession);
// setup notification builder
- builder.setStyle(mediaStyle)
- .setPriority(NotificationCompat.PRIORITY_HIGH)
- .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
- .setCategory(NotificationCompat.CATEGORY_TRANSPORT)
- .setShowWhen(false)
- .setSmallIcon(R.drawable.ic_newpipe_triangle_white)
- .setColor(ContextCompat.getColor(player.getContext(),
- R.color.dark_background_color))
+ final var builder = setupNotificationBuilder(player.getContext(), mediaStyle)
.setColorized(player.getPrefs().getBoolean(
- player.getContext().getString(R.string.notification_colorize_key), true))
- .setDeleteIntent(PendingIntentCompat.getBroadcast(player.getContext(),
- NOTIFICATION_ID, new Intent(ACTION_CLOSE), FLAG_UPDATE_CURRENT, false));
+ player.getContext().getString(R.string.notification_colorize_key), true));
// set the initial value for the video thumbnail, updatable with updateNotificationThumbnail
setLargeIcon(builder);
@@ -167,19 +159,17 @@ public final class NotificationUtil {
&& notificationBuilder.mActions.get(2).actionIntent != null);
}
+ public static void startForegroundWithDummyNotification(final PlayerService service) {
+ final var builder = setupNotificationBuilder(service, new MediaStyle());
+ startForeground(service, builder.build());
+ }
public void createNotificationAndStartForeground() {
if (notificationBuilder == null) {
notificationBuilder = createNotification();
}
updateNotification();
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- player.getService().startForeground(NOTIFICATION_ID, notificationBuilder.build(),
- ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK);
- } else {
- player.getService().startForeground(NOTIFICATION_ID, notificationBuilder.build());
- }
+ startForeground(player.getService(), notificationBuilder.build());
}
public void cancelNotificationAndStopForeground() {
@@ -193,6 +183,34 @@ public final class NotificationUtil {
}
+ /////////////////////////////////////////////////////
+ // STATIC FUNCTIONS IN COMMON BETWEEN DUMMY AND REAL NOTIFICATION
+ /////////////////////////////////////////////////////
+
+ private static NotificationCompat.Builder setupNotificationBuilder(final Context context,
+ final MediaStyle style) {
+ return new NotificationCompat.Builder(context,
+ context.getString(R.string.notification_channel_id))
+ .setStyle(style)
+ .setPriority(NotificationCompat.PRIORITY_HIGH)
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+ .setCategory(NotificationCompat.CATEGORY_TRANSPORT)
+ .setShowWhen(false)
+ .setSmallIcon(R.drawable.ic_newpipe_triangle_white)
+ .setColor(ContextCompat.getColor(context, R.color.dark_background_color))
+ .setDeleteIntent(PendingIntentCompat.getBroadcast(context,
+ NOTIFICATION_ID, new Intent(ACTION_CLOSE), FLAG_UPDATE_CURRENT, false));
+ }
+
+ private static void startForeground(final PlayerService service,
+ final Notification notification) {
+ // ServiceInfo constants are not used below Android Q, so 0 is set here
+ final int serviceType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
+ ? ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK : 0;
+ ServiceCompat.startForeground(service, NOTIFICATION_ID, notification, serviceType);
+ }
+
+
/////////////////////////////////////////////////////
// ACTIONS
/////////////////////////////////////////////////////
@@ -256,7 +274,9 @@ public final class NotificationUtil {
} else {
// We are playing in fragment. Don't open another activity just show fragment. That's it
final Intent intent = NavigationHelper.getPlayerIntent(
- player.getContext(), MainActivity.class, null, true);
+ player.getContext(), MainActivity.class, null,
+ PlayerIntentType.AllOthers);
+ intent.putExtra(Player.RESUME_PLAYBACK, true);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
diff --git a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java
index cfa2ab316..2a1b9d281 100644
--- a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java
+++ b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java
@@ -23,7 +23,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.BackpressureStrategy;
import io.reactivex.rxjava3.core.Flowable;
-import io.reactivex.rxjava3.subjects.BehaviorSubject;
+import io.reactivex.rxjava3.subjects.PublishSubject;
/**
* PlayQueue is responsible for keeping track of a list of streams and the index of
@@ -46,7 +46,7 @@ public abstract class PlayQueue implements Serializable {
private List backup;
private List streams;
- private transient BehaviorSubject eventBroadcast;
+ private transient PublishSubject eventBroadcast;
private transient Flowable broadcastReceiver;
private transient boolean disposed = false;
@@ -71,7 +71,7 @@ public abstract class PlayQueue implements Serializable {
*
*/
public void init() {
- eventBroadcast = BehaviorSubject.create();
+ eventBroadcast = PublishSubject.create();
broadcastReceiver = eventBroadcast.toFlowable(BackpressureStrategy.BUFFER)
.observeOn(AndroidSchedulers.mainThread())
@@ -291,6 +291,22 @@ public abstract class PlayQueue implements Serializable {
broadcast(new AppendEvent(itemList.size()));
}
+ /**
+ * Add the given item after the current stream.
+ *
+ * @param item item to add.
+ * @param skipIfSame if set, skip adding if the next stream is the same stream.
+ */
+ public void enqueueNext(@NonNull final PlayQueueItem item, final boolean skipIfSame) {
+ final int currentIndex = getIndex();
+ // if the next item is the same item as the one we want to enqueue, skip if flag is true
+ if (skipIfSame && item.isSameItem(getItem(currentIndex + 1))) {
+ return;
+ }
+ append(List.of(item));
+ move(size() - 1, currentIndex + 1);
+ }
+
/**
* Removes the item at the given index from the play queue.
*
@@ -529,8 +545,7 @@ public abstract class PlayQueue implements Serializable {
final PlayQueueItem stream = streams.get(i);
final PlayQueueItem otherStream = other.streams.get(i);
// Check is based on serviceId and URL
- if (stream.getServiceId() != otherStream.getServiceId()
- || !stream.getUrl().equals(otherStream.getUrl())) {
+ if (!stream.isSameItem(otherStream)) {
return false;
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueItem.java b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueItem.java
index 759c51267..d1d897c39 100644
--- a/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueItem.java
+++ b/app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueItem.java
@@ -38,7 +38,7 @@ public class PlayQueueItem implements Serializable {
private long recoveryPosition;
private Throwable error;
- PlayQueueItem(@NonNull final StreamInfo info) {
+ public PlayQueueItem(@NonNull final StreamInfo info) {
this(info.getName(), info.getUrl(), info.getServiceId(), info.getDuration(),
info.getThumbnails(), info.getUploaderName(),
info.getUploaderUrl(), info.getStreamType());
@@ -71,6 +71,22 @@ public class PlayQueueItem implements Serializable {
this.recoveryPosition = RECOVERY_UNSET;
}
+ /** Whether these two items should be treated as the same stream
+ * for the sake of keeping the same player running when e.g. jumping between timestamps.
+ *
+ * @param other the {@link PlayQueueItem} to compare against.
+ * @return whether the two items are the same so the stream can be re-used.
+ */
+ public boolean isSameItem(@Nullable final PlayQueueItem other) {
+ if (other == null) {
+ return false;
+ }
+ // We assume that the same service & URL uniquely determines
+ // that we can keep the same stream running.
+ return serviceId == other.serviceId
+ && url.equals(other.url);
+ }
+
@NonNull
public String getTitle() {
return title;
diff --git a/app/src/main/java/org/schabi/newpipe/player/playqueue/SinglePlayQueue.java b/app/src/main/java/org/schabi/newpipe/player/playqueue/SinglePlayQueue.java
index 0eb0f235a..f13d7924d 100644
--- a/app/src/main/java/org/schabi/newpipe/player/playqueue/SinglePlayQueue.java
+++ b/app/src/main/java/org/schabi/newpipe/player/playqueue/SinglePlayQueue.java
@@ -16,7 +16,9 @@ public final class SinglePlayQueue extends PlayQueue {
public SinglePlayQueue(final StreamInfo info) {
super(0, List.of(new PlayQueueItem(info)));
}
-
+ public SinglePlayQueue(final PlayQueueItem item) {
+ super(0, List.of(item));
+ }
public SinglePlayQueue(final StreamInfo info, final long startPosition) {
super(0, List.of(new PlayQueueItem(info)));
getItem().setRecoveryPosition(startPosition);
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
index d8efb30df..bfcc82984 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java
@@ -289,8 +289,10 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
binding.topControls.setClickable(true);
binding.topControls.setFocusable(true);
- binding.titleTextView.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
- binding.channelTextView.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
+ binding.metadataView.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
+
+ // Reset workaround changes from popup player
+ binding.audioTrackTextView.setMaxWidth(Integer.MAX_VALUE);
}
@Override
@@ -934,8 +936,7 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
}
fragmentListener.onFullscreenStateChanged(isFullscreen);
- binding.titleTextView.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
- binding.channelTextView.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
+ binding.metadataView.setVisibility(isFullscreen ? View.VISIBLE : View.GONE);
binding.playerCloseButton.setVisibility(isFullscreen ? View.GONE : View.VISIBLE);
setupScreenRotationButton();
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
index 6c98ab0fa..24b734fe0 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/PopupPlayerUi.java
@@ -40,6 +40,7 @@ import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.gesture.BasePlayerGestureListener;
import org.schabi.newpipe.player.gesture.PopupPlayerGestureListener;
import org.schabi.newpipe.player.helper.PlayerHelper;
+import org.schabi.newpipe.util.DeviceUtils;
public final class PopupPlayerUi extends VideoPlayerUi {
private static final String TAG = PopupPlayerUi.class.getSimpleName();
@@ -174,6 +175,8 @@ public final class PopupPlayerUi extends VideoPlayerUi {
binding.topControls.setClickable(false);
binding.topControls.setFocusable(false);
binding.bottomControls.bringToFront();
+ // Workaround that UI elements are pushed off screen
+ binding.audioTrackTextView.setMaxWidth(DeviceUtils.dpToPx(48, context));
super.setupElementsVisibility();
}
diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
index 7157d6af2..b68d3d94d 100644
--- a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
+++ b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java
@@ -1554,6 +1554,11 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa
@Override
public void onVideoSizeChanged(@NonNull final VideoSize videoSize) {
super.onVideoSizeChanged(videoSize);
+ // Starting with ExoPlayer 2.19.0, the VideoSize will report a width and height of 0
+ // if the renderer is disabled. In that case, we skip updating the aspect ratio.
+ if (videoSize.width == 0 || videoSize.height == 0) {
+ return;
+ }
binding.surfaceView.setAspectRatio(((float) videoSize.width) / videoSize.height);
}
//endregion
diff --git a/app/src/main/java/org/schabi/newpipe/settings/BackupRestoreSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/BackupRestoreSettingsFragment.java
index 321ad65da..baaa93e44 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/BackupRestoreSettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/BackupRestoreSettingsFragment.java
@@ -40,6 +40,8 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
@@ -96,10 +98,9 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
return true;
});
- final Preference resetSettings = findPreference(getString(R.string.reset_settings));
+ final Preference resetSettings = requirePreference(R.string.reset_settings);
// Resets all settings by deleting shared preference and restarting the app
// A dialogue will pop up to confirm if user intends to reset all settings
- assert resetSettings != null;
resetSettings.setOnPreferenceClickListener(preference -> {
// Show Alert Dialogue
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
@@ -155,9 +156,9 @@ public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
}
private void exportDatabase(final StoredFileHelper file, final Uri exportDataUri) {
- try {
+ try (ExecutorService executor = Executors.newSingleThreadExecutor()) {
//checkpoint before export
- NewPipeDatabase.checkpoint();
+ executor.submit(NewPipeDatabase::checkpoint).get();
final SharedPreferences preferences = PreferenceManager
.getDefaultSharedPreferences(requireContext());
diff --git a/app/src/main/java/org/schabi/newpipe/settings/BasePreferenceFragment.java b/app/src/main/java/org/schabi/newpipe/settings/BasePreferenceFragment.java
index 619579f3a..21cba3daa 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/BasePreferenceFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/BasePreferenceFragment.java
@@ -48,8 +48,8 @@ public abstract class BasePreferenceFragment extends PreferenceFragmentCompat {
}
@NonNull
- public final Preference requirePreference(@StringRes final int resId) {
- final Preference preference = findPreference(getString(resId));
+ public final T requirePreference(@StringRes final int resId) {
+ final T preference = findPreference(getString(resId));
Objects.requireNonNull(preference);
return preference;
}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/DebugSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/DebugSettingsFragment.java
index d78ade49d..82f2f5bb6 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/DebugSettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/DebugSettingsFragment.java
@@ -22,27 +22,20 @@ public class DebugSettingsFragment extends BasePreferenceFragment {
addPreferencesFromResourceRegistry();
final Preference allowHeapDumpingPreference =
- findPreference(getString(R.string.allow_heap_dumping_key));
+ requirePreference(R.string.allow_heap_dumping_key);
final Preference showMemoryLeaksPreference =
- findPreference(getString(R.string.show_memory_leaks_key));
+ requirePreference(R.string.show_memory_leaks_key);
final Preference showImageIndicatorsPreference =
- findPreference(getString(R.string.show_image_indicators_key));
+ requirePreference(R.string.show_image_indicators_key);
final Preference checkNewStreamsPreference =
- findPreference(getString(R.string.check_new_streams_key));
+ requirePreference(R.string.check_new_streams_key);
final Preference crashTheAppPreference =
- findPreference(getString(R.string.crash_the_app_key));
+ requirePreference(R.string.crash_the_app_key);
final Preference showErrorSnackbarPreference =
- findPreference(getString(R.string.show_error_snackbar_key));
+ requirePreference(R.string.show_error_snackbar_key);
final Preference createErrorNotificationPreference =
- findPreference(getString(R.string.create_error_notification_key));
+ requirePreference(R.string.create_error_notification_key);
- assert allowHeapDumpingPreference != null;
- assert showMemoryLeaksPreference != null;
- assert showImageIndicatorsPreference != null;
- assert checkNewStreamsPreference != null;
- assert crashTheAppPreference != null;
- assert showErrorSnackbarPreference != null;
- assert createErrorNotificationPreference != null;
final Optional optBVLeakCanary = getBVDLeakCanary();
diff --git a/app/src/main/java/org/schabi/newpipe/settings/MainSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/MainSettingsFragment.java
index 32e33d55b..cb3de39a0 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/MainSettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/MainSettingsFragment.java
@@ -25,7 +25,7 @@ public class MainSettingsFragment extends BasePreferenceFragment {
// Check if the app is updatable
if (!ReleaseVersionUtil.INSTANCE.isReleaseApk()) {
getPreferenceScreen().removePreference(
- findPreference(getString(R.string.update_pref_screen_key)));
+ requirePreference(R.string.update_pref_screen_key));
defaultPreferences.edit().putBoolean(getString(R.string.update_app_key), false).apply();
}
@@ -33,7 +33,7 @@ public class MainSettingsFragment extends BasePreferenceFragment {
// Hide debug preferences in RELEASE build variant
if (!DEBUG) {
getPreferenceScreen().removePreference(
- findPreference(getString(R.string.debug_pref_screen_key)));
+ requirePreference(R.string.debug_pref_screen_key));
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java b/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java
index 0a5512c69..7cb1564b3 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java
@@ -103,12 +103,12 @@ public final class NewPipeSettings {
}
public static boolean useStorageAccessFramework(final Context context) {
- // There's a FireOS bug which prevents SAF open/close dialogs from being confirmed with a
- // remote (see #6455).
- if (DeviceUtils.isFireTv()) {
- return false;
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return true;
+ } else if (DeviceUtils.isFireTv()) {
+ // There's a FireOS bug which prevents SAF open/close dialogs from being confirmed with
+ // a remote (see #6455).
+ return false;
}
final String key = context.getString(R.string.storage_use_saf);
diff --git a/app/src/main/java/org/schabi/newpipe/settings/NotificationsSettingsFragment.kt b/app/src/main/java/org/schabi/newpipe/settings/NotificationsSettingsFragment.kt
index 2d3344c09..d6b0a84da 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/NotificationsSettingsFragment.kt
+++ b/app/src/main/java/org/schabi/newpipe/settings/NotificationsSettingsFragment.kt
@@ -29,8 +29,7 @@ class NotificationsSettingsFragment : BasePreferenceFragment(), OnSharedPreferen
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.notifications_settings)
- streamsNotificationsPreference =
- findPreference(getString(R.string.enable_streams_notifications))
+ streamsNotificationsPreference = requirePreference(R.string.enable_streams_notifications)
// main check is done in onResume, but also do it here to prevent flickering
updateEnabledState(NotificationHelper.areNotificationsEnabledOnDevice(requireContext()))
@@ -125,8 +124,8 @@ class NotificationsSettingsFragment : BasePreferenceFragment(), OnSharedPreferen
private fun updateSubscriptions(subscriptions: List) {
val notified = subscriptions.count { it.notificationMode != NotificationMode.DISABLED }
- val preference = findPreference(getString(R.string.streams_notifications_channels_key))
- preference?.apply { summary = "$notified/${subscriptions.size}" }
+ val preference = requirePreference(R.string.streams_notifications_channels_key)
+ preference.summary = "$notified/${subscriptions.size}"
}
private fun onError(e: Throwable) {
diff --git a/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java b/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java
index 1158b3d83..81fddbcfb 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java
@@ -396,7 +396,8 @@ public class PeertubeInstanceListFragment extends Fragment {
}
}
- private static class PeertubeInstanceCallback extends DiffUtil.ItemCallback {
+ private static final class PeertubeInstanceCallback
+ extends DiffUtil.ItemCallback {
@Override
public boolean areItemsTheSame(@NonNull final PeertubeInstance oldItem,
@NonNull final PeertubeInstance newItem) {
diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java
index 37335421d..18e0816bb 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/SelectChannelFragment.java
@@ -174,7 +174,7 @@ public class SelectChannelFragment extends DialogFragment {
void onCancel();
}
- private class SelectChannelAdapter
+ private final class SelectChannelAdapter
extends RecyclerView.Adapter {
@NonNull
@Override
diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectFeedGroupFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectFeedGroupFragment.java
index 662379369..c106f5998 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/SelectFeedGroupFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/SelectFeedGroupFragment.java
@@ -175,7 +175,7 @@ public class SelectFeedGroupFragment extends DialogFragment {
void onCancel();
}
- private class SelectFeedGroupAdapter
+ private final class SelectFeedGroupAdapter
extends RecyclerView.Adapter {
@NonNull
@Override
diff --git a/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java
index 36abef9e5..880cbb282 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/SelectPlaylistFragment.java
@@ -118,12 +118,12 @@ public class SelectPlaylistFragment extends DialogFragment {
if (selectedItem instanceof PlaylistMetadataEntry) {
final PlaylistMetadataEntry entry = ((PlaylistMetadataEntry) selectedItem);
- onSelectedListener.onLocalPlaylistSelected(entry.getUid(), entry.name);
+ onSelectedListener.onLocalPlaylistSelected(entry.getUid(), entry.getOrderingName());
} else if (selectedItem instanceof PlaylistRemoteEntity) {
final PlaylistRemoteEntity entry = ((PlaylistRemoteEntity) selectedItem);
onSelectedListener.onRemotePlaylistSelected(
- entry.getServiceId(), entry.getUrl(), entry.getName());
+ entry.getServiceId(), entry.getUrl(), entry.getOrderingName());
}
}
dismiss();
@@ -138,7 +138,7 @@ public class SelectPlaylistFragment extends DialogFragment {
void onRemotePlaylistSelected(int serviceId, String url, String name);
}
- private class SelectPlaylistAdapter
+ private final class SelectPlaylistAdapter
extends RecyclerView.Adapter {
@NonNull
@Override
@@ -157,14 +157,15 @@ public class SelectPlaylistFragment extends DialogFragment {
if (selectedItem instanceof PlaylistMetadataEntry) {
final PlaylistMetadataEntry entry = ((PlaylistMetadataEntry) selectedItem);
- holder.titleView.setText(entry.name);
+ holder.titleView.setText(entry.getOrderingName());
holder.view.setOnClickListener(view -> clickedItem(position));
- PicassoHelper.loadPlaylistThumbnail(entry.thumbnailUrl).into(holder.thumbnailView);
+ PicassoHelper.loadPlaylistThumbnail(entry.getThumbnailUrl())
+ .into(holder.thumbnailView);
} else if (selectedItem instanceof PlaylistRemoteEntity) {
final PlaylistRemoteEntity entry = ((PlaylistRemoteEntity) selectedItem);
- holder.titleView.setText(entry.getName());
+ holder.titleView.setText(entry.getOrderingName());
holder.view.setOnClickListener(view -> clickedItem(position));
PicassoHelper.loadPlaylistThumbnail(entry.getThumbnailUrl())
.into(holder.thumbnailView);
diff --git a/app/src/main/java/org/schabi/newpipe/settings/UpdateSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/UpdateSettingsFragment.java
index b8d0aa556..8923972b0 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/UpdateSettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/UpdateSettingsFragment.java
@@ -34,9 +34,9 @@ public class UpdateSettingsFragment extends BasePreferenceFragment {
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
addPreferencesFromResourceRegistry();
- findPreference(getString(R.string.update_app_key))
+ requirePreference(R.string.update_app_key)
.setOnPreferenceChangeListener(updatePreferenceChange);
- findPreference(getString(R.string.manual_update_key))
+ requirePreference(R.string.manual_update_key)
.setOnPreferenceClickListener(manualUpdateClick);
}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/VideoAudioSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/VideoAudioSettingsFragment.java
index a1f563724..c5c4c480c 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/VideoAudioSettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/VideoAudioSettingsFragment.java
@@ -90,12 +90,12 @@ public class VideoAudioSettingsFragment extends BasePreferenceFragment {
showHigherResolutions);
// get resolution preferences
- final ListPreference defaultResolution = findPreference(
- getString(R.string.default_resolution_key));
- final ListPreference defaultPopupResolution = findPreference(
- getString(R.string.default_popup_resolution_key));
- final ListPreference mobileDataResolution = findPreference(
- getString(R.string.limit_mobile_data_usage_key));
+ final ListPreference defaultResolution = requirePreference(
+ R.string.default_resolution_key);
+ final ListPreference defaultPopupResolution = requirePreference(
+ R.string.default_popup_resolution_key);
+ final ListPreference mobileDataResolution = requirePreference(
+ R.string.limit_mobile_data_usage_key);
// update resolution preferences with new resolutions, entries & values for each
defaultResolution.setEntries(resolutionListDescriptions.toArray(new String[0]));
@@ -161,8 +161,7 @@ public class VideoAudioSettingsFragment extends BasePreferenceFragment {
}
}
- final ListPreference durations = findPreference(
- getString(R.string.seek_duration_key));
+ final ListPreference durations = requirePreference(R.string.seek_duration_key);
durations.setEntryValues(displayedDurationValues.toArray(new CharSequence[0]));
durations.setEntries(displayedDescriptionValues.toArray(new CharSequence[0]));
final int selectedDuration = Integer.parseInt(durations.getValue());
diff --git a/app/src/main/java/org/schabi/newpipe/settings/notifications/NotificationModeConfigAdapter.kt b/app/src/main/java/org/schabi/newpipe/settings/notifications/NotificationModeConfigAdapter.kt
index f61aa72ab..fd8abfa16 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/notifications/NotificationModeConfigAdapter.kt
+++ b/app/src/main/java/org/schabi/newpipe/settings/notifications/NotificationModeConfigAdapter.kt
@@ -31,7 +31,7 @@ class NotificationModeConfigAdapter(
fun update(newData: List) {
val items = newData.map {
- SubscriptionItem(it.uid, it.name, it.notificationMode, it.serviceId, it.url)
+ SubscriptionItem(it.uid, it.name!!, it.notificationMode, it.serviceId, it.url!!)
}
submitList(items)
}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/preferencesearch/PreferenceSearchAdapter.java b/app/src/main/java/org/schabi/newpipe/settings/preferencesearch/PreferenceSearchAdapter.java
index d6e2021a1..dd59ba86e 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/preferencesearch/PreferenceSearchAdapter.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/preferencesearch/PreferenceSearchAdapter.java
@@ -69,7 +69,8 @@ class PreferenceSearchAdapter
}
}
- private static class PreferenceCallback extends DiffUtil.ItemCallback {
+ private static final class PreferenceCallback
+ extends DiffUtil.ItemCallback {
@Override
public boolean areItemsTheSame(@NonNull final PreferenceSearchItem oldItem,
@NonNull final PreferenceSearchItem newItem) {
diff --git a/app/src/main/java/org/schabi/newpipe/streams/OggFromWebMWriter.java b/app/src/main/java/org/schabi/newpipe/streams/OggFromWebMWriter.java
index 266cec24a..7cdc84e22 100644
--- a/app/src/main/java/org/schabi/newpipe/streams/OggFromWebMWriter.java
+++ b/app/src/main/java/org/schabi/newpipe/streams/OggFromWebMWriter.java
@@ -1,8 +1,14 @@
package org.schabi.newpipe.streams;
+import static org.schabi.newpipe.MainActivity.DEBUG;
+
+import android.util.Log;
+import android.util.Pair;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.streams.WebMReader.Cluster;
import org.schabi.newpipe.streams.WebMReader.Segment;
import org.schabi.newpipe.streams.WebMReader.SimpleBlock;
@@ -13,6 +19,10 @@ import java.io.Closeable;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
/**
* @author kapodamy
@@ -52,8 +62,10 @@ public class OggFromWebMWriter implements Closeable {
private long segmentTableNextTimestamp = TIME_SCALE_NS;
private final int[] crc32Table = new int[256];
+ private final StreamInfo streamInfo;
- public OggFromWebMWriter(@NonNull final SharpStream source, @NonNull final SharpStream target) {
+ public OggFromWebMWriter(@NonNull final SharpStream source, @NonNull final SharpStream target,
+ @Nullable final StreamInfo streamInfo) {
if (!source.canRead() || !source.canRewind()) {
throw new IllegalArgumentException("source stream must be readable and allows seeking");
}
@@ -63,6 +75,7 @@ public class OggFromWebMWriter implements Closeable {
this.source = source;
this.output = target;
+ this.streamInfo = streamInfo;
this.streamId = (int) System.currentTimeMillis();
@@ -271,12 +284,31 @@ public class OggFromWebMWriter implements Closeable {
@Nullable
private byte[] makeMetadata() {
+ if (DEBUG) {
+ Log.d("OggFromWebMWriter", "Downloading media with codec ID " + webmTrack.codecId);
+ }
+
if ("A_OPUS".equals(webmTrack.codecId)) {
- return new byte[]{
- 0x4F, 0x70, 0x75, 0x73, 0x54, 0x61, 0x67, 0x73, // "OpusTags" binary string
- 0x00, 0x00, 0x00, 0x00, // writing application string size (not present)
- 0x00, 0x00, 0x00, 0x00 // additional tags count (zero means no tags)
- };
+ final var metadata = new ArrayList>();
+ if (streamInfo != null) {
+ metadata.add(Pair.create("COMMENT", streamInfo.getUrl()));
+ metadata.add(Pair.create("GENRE", streamInfo.getCategory()));
+ metadata.add(Pair.create("ARTIST", streamInfo.getUploaderName()));
+ metadata.add(Pair.create("TITLE", streamInfo.getName()));
+ metadata.add(Pair.create("DATE", streamInfo
+ .getUploadDate()
+ .getLocalDateTime()
+ .format(DateTimeFormatter.ISO_DATE)));
+ }
+
+ if (DEBUG) {
+ Log.d("OggFromWebMWriter", "Creating metadata header with this data:");
+ metadata.forEach(p -> {
+ Log.d("OggFromWebMWriter", p.first + "=" + p.second);
+ });
+ }
+
+ return makeOpusTagsHeader(metadata);
} else if ("A_VORBIS".equals(webmTrack.codecId)) {
return new byte[]{
0x03, // ¿¿¿???
@@ -290,6 +322,59 @@ public class OggFromWebMWriter implements Closeable {
return null;
}
+ /**
+ * This creates a single metadata tag for use in opus metadata headers. It contains the four
+ * byte string length field and includes the string as-is. This cannot be used independently,
+ * but must follow a proper "OpusTags" header.
+ *
+ * @param pair A key-value pair in the format "KEY=some value"
+ * @return The binary data of the encoded metadata tag
+ */
+ private static byte[] makeOpusMetadataTag(final Pair pair) {
+ final var keyValue = pair.first.toUpperCase() + "=" + pair.second.trim();
+
+ final var bytes = keyValue.getBytes();
+ final var buf = ByteBuffer.allocate(4 + bytes.length);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+ buf.putInt(bytes.length);
+ buf.put(bytes);
+ return buf.array();
+ }
+
+ /**
+ * This returns a complete "OpusTags" header, created from the provided metadata tags.
+ *
+ * You probably want to use makeOpusMetadata(), which uses this function to create
+ * a header with sensible metadata filled in.
+ *
+ * @param keyValueLines A list of pairs of the tags. This can also be though of as a mapping
+ * from one key to multiple values.
+ * @return The binary header
+ */
+ private static byte[] makeOpusTagsHeader(final List> keyValueLines) {
+ final var tags = keyValueLines
+ .stream()
+ .filter(p -> !p.second.isBlank())
+ .map(OggFromWebMWriter::makeOpusMetadataTag)
+ .collect(Collectors.toUnmodifiableList());
+
+ final var tagsBytes = tags.stream().collect(Collectors.summingInt(arr -> arr.length));
+
+ // Fixed header fields + dynamic fields
+ final var byteCount = 16 + tagsBytes;
+
+ final var head = ByteBuffer.allocate(byteCount);
+ head.order(ByteOrder.LITTLE_ENDIAN);
+ head.put(new byte[]{
+ 0x4F, 0x70, 0x75, 0x73, 0x54, 0x61, 0x67, 0x73, // "OpusTags" binary string
+ 0x00, 0x00, 0x00, 0x00, // vendor (aka. Encoder) string of length 0
+ });
+ head.putInt(tags.size()); // 4 bytes for tag count
+ tags.forEach(head::put); // dynamic amount of tag bytes
+
+ return head.array();
+ }
+
private void write(final ByteBuffer buffer) throws IOException {
output.write(buffer.array(), 0, buffer.position());
buffer.position(0);
diff --git a/app/src/main/java/org/schabi/newpipe/streams/SrtFromTtmlWriter.java b/app/src/main/java/org/schabi/newpipe/streams/SrtFromTtmlWriter.java
index 7aff655a0..8c8dc175b 100644
--- a/app/src/main/java/org/schabi/newpipe/streams/SrtFromTtmlWriter.java
+++ b/app/src/main/java/org/schabi/newpipe/streams/SrtFromTtmlWriter.java
@@ -15,7 +15,11 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
- * @author kapodamy
+ * Converts TTML subtitles to SRT format.
+ *
+ * References:
+ * - TTML 2.0 (W3C): https://www.w3.org/TR/ttml2/
+ * - SRT format: https://en.wikipedia.org/wiki/SubRip
*/
public class SrtFromTtmlWriter {
private static final String NEW_LINE = "\r\n";
@@ -24,7 +28,11 @@ public class SrtFromTtmlWriter {
private final boolean ignoreEmptyFrames;
private final Charset charset = StandardCharsets.UTF_8;
- private int frameIndex = 0;
+ // According to the SubRip (.srt) specification, subtitle
+ // numbering must start from 1.
+ // Some players accept 0 or even negative indices,
+ // but to ensure compliance we start at 1.
+ private int frameIndex = 1;
public SrtFromTtmlWriter(final SharpStream out, final boolean ignoreEmptyFrames) {
this.out = out;
@@ -39,7 +47,8 @@ public class SrtFromTtmlWriter {
private void writeFrame(final String begin, final String end, final StringBuilder text)
throws IOException {
- writeString(String.valueOf(frameIndex++));
+ writeString(String.valueOf(frameIndex));
+ frameIndex += 1;
writeString(NEW_LINE);
writeString(begin);
writeString(" --> ");
@@ -54,6 +63,226 @@ public class SrtFromTtmlWriter {
out.write(text.getBytes(charset));
}
+ /**
+ * Decode XML or HTML entities into their actual (literal) characters.
+ *
+ * TTML is XML-based, so text nodes may contain escaped entities
+ * instead of direct characters. For example:
+ *
+ * "&" → "&"
+ * "<" → "<"
+ * ">" → ">"
+ * " " → "\t" (TAB)
+ * "
" (
) → "\n" (LINE FEED)
+ *
+ * XML files cannot contain characters like "<", ">", "&" directly,
+ * so they must be represented using their entity-encoded forms.
+ *
+ * Jsoup sometimes leaves nested or encoded entities unresolved
+ * (e.g. inside text nodes in TTML files), so this function
+ * acts as a final “safety net” to ensure all entities are decoded
+ * before further normalization.
+ *
+ * Character representation layers for reference:
+ * - Literal characters: <, >, &
+ * → appear in runtime/output text (e.g. final SRT output)
+ * - Escaped entities: <, >, &
+ * → appear in XML/HTML/TTML source files
+ * - Numeric entities: , ,
+ * → appear mainly in XML/TTML files (also valid in HTML)
+ * for non-printable or special characters
+ * - Unicode escapes: \u00A0 (Java/Unicode internal form)
+ * → appear only in Java source code (NOT valid in XML)
+ *
+ * XML entities include both named (&, <) and numeric
+ * ( , ) forms.
+ *
+ * @param encodedEntities The raw text fragment possibly containing
+ * encoded XML entities.
+ * @return A decoded string where all entities are replaced by their
+ * actual (literal) characters.
+ */
+ private String decodeXmlEntities(final String encodedEntities) {
+ return Parser.unescapeEntities(encodedEntities, true);
+ }
+
+ /**
+ * Handle rare XML entity characters like LF:
(`\n`),
+ * CR:
(`\r`) and CRLF: (`\r\n`).
+ *
+ * These are technically valid in TTML (XML allows them)
+ * but unusual in practice, since most TTML line breaks
+ * are represented as
tags instead.
+ * As a defensive approach, we normalize them:
+ *
+ * - Windows (\r\n), macOS (\r), and Unix (\n) → unified SRT NEW_LINE (\r\n)
+ *
+ * Although well-formed TTML normally encodes line breaks
+ * as
tags, some auto-generated or malformed TTML files
+ * may embed literal newline entities (
,
). This
+ * normalization ensures these cases render properly in SRT
+ * players instead of breaking the subtitle structure.
+ *
+ * @param text To be normalized text with actual characters.
+ * @return Unified SRT NEW_LINE converted from all kinds of line breaks.
+ */
+ private String normalizeLineBreakForSrt(final String text) {
+ String cleaned = text;
+
+ // NOTE:
+ // The order of newline replacements must NOT change,
+ // or duplicated line breaks (e.g. \r\n → \n\n) will occur.
+ cleaned = cleaned.replace("\r\n", "\n")
+ .replace("\r", "\n");
+
+ cleaned = cleaned.replace("\n", NEW_LINE);
+
+ return cleaned;
+ }
+
+ private String normalizeForSrt(final String actualText) {
+ String cleaned = actualText;
+
+ // Replace NBSP "non-breaking space" (\u00A0) with regular space ' '(\u0020).
+ //
+ // Why:
+ // - Some viewers render NBSP(\u00A0) incorrectly:
+ // * MPlayer 1.5: shown as “??”
+ // * Linux command `cat -A`: displayed as control-like markers
+ // (M-BM-)
+ // * Acode (Android editor): displayed as visible replacement
+ // glyphs (red dots)
+ // - Other viewers show it as a normal space (e.g., VS Code 1.104.0,
+ // vlc 3.0.20, mpv 0.37.0, Totem 43.0)
+ // → Mixed rendering creates inconsistency and may confuse users.
+ //
+ // Details:
+ // - YouTube TTML subtitles use both regular spaces (\u0020)
+ // and non-breaking spaces (\u00A0).
+ // - SRT subtitles only support regular spaces (\u0020),
+ // so \u00A0 may cause display issues.
+ // - \u00A0 and \u0020 are visually identical (i.e., they both
+ // appear as spaces ' '), but they differ in Unicode encoding,
+ // and NBSP (\u00A0) renders differently in different viewers.
+ // - SRT is a plain-text format and does not interpret
+ // "non-breaking" behavior.
+ //
+ // Conclusion:
+ // - Ensure uniform behavior, so replace it to a regular space
+ // without "non-breaking" behavior.
+ //
+ // References:
+ // - Unicode U+00A0 NBSP (Latin-1 Supplement):
+ // https://unicode.org/charts/PDF/U0080.pdf
+ cleaned = cleaned.replace('\u00A0', ' ') // Non-breaking space
+ .replace('\u202F', ' ') // Narrow no-break space
+ .replace('\u205F', ' ') // Medium mathematical space
+ .replace('\u3000', ' ') // Ideographic space
+ // \u2000 ~ \u200A are whitespace characters (e.g.,
+ // en space, em space), replaced with regular space (\u0020).
+ .replaceAll("[\\u2000-\\u200A]", " "); // Whitespace characters
+
+ // \u200B ~ \u200F are a range of non-spacing characters
+ // (e.g., zero-width space, zero-width non-joiner, etc.),
+ // which have no effect in *.SRT files and may cause
+ // display issues.
+ // These characters are invisible to the human eye, and
+ // they still exist in the encoding, so they need to be
+ // removed.
+ // After removal, the actual content becomes completely
+ // empty "", meaning there are no characters left, just
+ // an empty space, which helps avoid formatting issues
+ // in subtitles.
+ cleaned = cleaned.replaceAll("[\\u200B-\\u200F]", ""); // Non-spacing characters
+
+ // Remove control characters (\u0000 ~ \u001F, except
+ // \n, \r, \t).
+ // - These are ASCII C0 control codes (e.g. \u0001 SOH,
+ // \u0008 BS, \u001F US), invisible and irrelevant in
+ // subtitles, may cause square boxes (?) in players.
+ // - Reference:
+ // Unicode Basic Latin (https://unicode.org/charts/PDF/U0000.pdf)
+ // ASCII Control (https://en.wikipedia.org/wiki/ASCII#Control_characters)
+ cleaned = cleaned.replaceAll("[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F]", "");
+
+ // Reasoning:
+ // - subtitle files generally don't require tabs for alignment.
+ // - Tabs can be displayed with varying widths across different
+ // editors or platforms, which may cause display issues.
+ // - Replace it with a single space for consistent display
+ // across different editors or platforms.
+ cleaned = cleaned.replace('\t', ' ');
+
+ cleaned = normalizeLineBreakForSrt(cleaned);
+
+ return cleaned;
+ }
+
+ private String sanitizeFragment(final String raw) {
+ if (null == raw) {
+ return "";
+ }
+
+ final String actualCharacters = decodeXmlEntities(raw);
+
+ final String srtSafeText = normalizeForSrt(actualCharacters);
+
+ return srtSafeText;
+ }
+
+ // Recursively process all child nodes to ensure text inside
+ // nested tags (e.g., ) is also extracted.
+ private void traverseChildNodesForNestedTags(final Node parent,
+ final StringBuilder text) {
+ for (final Node child : parent.childNodes()) {
+ extractText(child, text);
+ }
+ }
+
+ // CHECKSTYLE:OFF checkstyle:JavadocStyle
+ // checkstyle does not understand that span tags are inside a code block
+ /**
+ * Recursive method to extract text from all nodes.
+ *
+ * This method processes {@link TextNode}s and {@code
} tags,
+ * recursively extracting text from nested tags
+ * (e.g. extracting text from nested {@code } tags).
+ * Newlines are added for {@code
} tags.
+ *
+ * @param node the current node to process
+ * @param text the {@link StringBuilder} to append the extracted text to
+ */
+ // --------------------------------------------------------------------
+ // [INTERNAL NOTE] TTML text layer explanation
+ //
+ // TTML parsing involves multiple text "layers":
+ // 1. Raw XML entities (e.g., <, ) are decoded by Jsoup.
+ // 2. extractText() works on DOM TextNodes (already parsed strings).
+ // 3. sanitizeFragment() decodes remaining entities and fixes
+ // Unicode quirks.
+ // 4. normalizeForSrt() ensures literal text is safe for SRT output.
+ //
+ // In short:
+ // Jsoup handles XML-level syntax,
+ // our code handles text-level normalization for subtitles.
+ // --------------------------------------------------------------------
+ private void extractText(final Node node, final StringBuilder text) {
+ if (node instanceof TextNode textNode) {
+ String rawTtmlFragment = textNode.getWholeText();
+ String srtContent = sanitizeFragment(rawTtmlFragment);
+ text.append(srtContent);
+ } else if (node instanceof Element element) {
+ //
is a self-closing HTML tag used to insert a line break.
+ if (element.tagName().equalsIgnoreCase("br")) {
+ // Add a newline for
tags
+ text.append(NEW_LINE);
+ }
+ }
+
+ traverseChildNodesForNestedTags(node, text);
+ }
+ // CHECKSTYLE:ON
+
public void build(final SharpStream ttml) throws IOException {
/*
* TTML parser with BASIC support
@@ -74,21 +303,15 @@ public class SrtFromTtmlWriter {
final Elements paragraphList = doc.select("body > div > p");
// check if has frames
- if (paragraphList.size() < 1) {
+ if (paragraphList.isEmpty()) {
return;
}
for (final Element paragraph : paragraphList) {
text.setLength(0);
- for (final Node children : paragraph.childNodes()) {
- if (children instanceof TextNode) {
- text.append(((TextNode) children).text());
- } else if (children instanceof Element
- && ((Element) children).tagName().equalsIgnoreCase("br")) {
- text.append(NEW_LINE);
- }
- }
+ // Recursively extract text from all child nodes
+ extractText(paragraph, text);
if (ignoreEmptyFrames && text.length() < 1) {
continue;
diff --git a/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java
deleted file mode 100644
index 5aa332159..000000000
--- a/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package org.schabi.newpipe.util;
-
-import android.content.Context;
-
-import org.schabi.newpipe.R;
-
-/**
- * Created by Christian Schabesberger on 28.09.17.
- * KioskTranslator.java is part of NewPipe.
- *
- * NewPipe is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- *
- * NewPipe is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
- * You should have received a copy of the GNU General Public License
- * along with NewPipe. If not, see .
- *
- */
-
-public final class KioskTranslator {
- private KioskTranslator() { }
-
- public static String getTranslatedKioskName(final String kioskId, final Context c) {
- switch (kioskId) {
- case "Trending":
- return c.getString(R.string.trending);
- case "Top 50":
- return c.getString(R.string.top_50);
- case "New & hot":
- return c.getString(R.string.new_and_hot);
- case "Local":
- return c.getString(R.string.local);
- case "Recently added":
- return c.getString(R.string.recently_added);
- case "Most liked":
- return c.getString(R.string.most_liked);
- case "conferences":
- return c.getString(R.string.conferences);
- case "recent":
- return c.getString(R.string.recent);
- case "live":
- return c.getString(R.string.duration_live);
- case "Featured":
- return c.getString(R.string.featured);
- case "Radio":
- return c.getString(R.string.radio);
- case "trending_gaming":
- return c.getString(R.string.trending_gaming);
- case "trending_music":
- return c.getString(R.string.trending_music);
- case "trending_movies_and_shows":
- return c.getString(R.string.trending_movies);
- case "trending_podcasts_episodes":
- return c.getString(R.string.trending_podcasts);
- default:
- return kioskId;
- }
- }
-
- public static int getKioskIcon(final String kioskId) {
- switch (kioskId) {
- case "Trending":
- case "Top 50":
- case "New & hot":
- case "conferences":
- return R.drawable.ic_whatshot;
- case "Local":
- return R.drawable.ic_home;
- case "Recently added":
- case "recent":
- return R.drawable.ic_add_circle_outline;
- case "Most liked":
- return R.drawable.ic_thumb_up;
- case "live":
- return R.drawable.ic_live_tv;
- case "Featured":
- return R.drawable.ic_stars;
- case "Radio":
- return R.drawable.ic_radio;
- case "trending_gaming":
- return R.drawable.ic_videogame_asset;
- case "trending_music":
- return R.drawable.ic_music_note;
- case "trending_movies_and_shows":
- return R.drawable.ic_movie;
- case "trending_podcasts_episodes":
- return R.drawable.ic_podcasts;
- default:
- return 0;
- }
- }
-}
diff --git a/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.kt b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.kt
new file mode 100644
index 000000000..1f86f5db7
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.kt
@@ -0,0 +1,52 @@
+/*
+ * SPDX-FileCopyrightText: 2017-2025 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.util
+
+import android.content.Context
+import org.schabi.newpipe.R
+
+object KioskTranslator {
+ @JvmStatic
+ fun getTranslatedKioskName(kioskId: String, context: Context): String {
+ return when (kioskId) {
+ "Trending" -> context.getString(R.string.trending)
+ "Top 50" -> context.getString(R.string.top_50)
+ "New & hot" -> context.getString(R.string.new_and_hot)
+ "Local" -> context.getString(R.string.local)
+ "Recently added" -> context.getString(R.string.recently_added)
+ "Most liked" -> context.getString(R.string.most_liked)
+ "conferences" -> context.getString(R.string.conferences)
+ "recent" -> context.getString(R.string.recent)
+ "live" -> context.getString(R.string.duration_live)
+ "Featured" -> context.getString(R.string.featured)
+ "Radio" -> context.getString(R.string.radio)
+ "trending_gaming" -> context.getString(R.string.trending_gaming)
+ "trending_music" -> context.getString(R.string.trending_music)
+ "trending_movies_and_shows" -> context.getString(R.string.trending_movies)
+ "trending_podcasts_episodes" -> context.getString(R.string.trending_podcasts)
+ else -> kioskId
+ }
+ }
+
+ @JvmStatic
+ fun getKioskIcon(kioskId: String): Int {
+ return when (kioskId) {
+ "Trending", "Top 50", "New & hot", "conferences" -> R.drawable.ic_whatshot
+ "Local" -> R.drawable.ic_home
+ "Recently added", "recent" -> R.drawable.ic_add_circle_outline
+ "Most liked" -> R.drawable.ic_thumb_up
+ "live" -> R.drawable.ic_live_tv
+ "Featured" -> R.drawable.ic_stars
+ "Radio" -> R.drawable.ic_radio
+ "trending_gaming" -> R.drawable.ic_videogame_asset
+ "trending_music" -> R.drawable.ic_music_note
+ "trending_movies_and_shows" -> R.drawable.ic_movie
+ "trending_podcasts_episodes" -> R.drawable.ic_podcasts
+ else -> 0
+ }
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
index ea41f3e81..409fcb30c 100644
--- a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java
@@ -806,7 +806,7 @@ public final class ListHelper {
final Locale preferredLanguage = Localization.getPreferredLocale(context);
final boolean preferOriginalAudio =
preferences.getBoolean(context.getString(R.string.prefer_original_audio_key),
- false);
+ true);
final boolean preferDescriptiveAudio =
preferences.getBoolean(context.getString(R.string.prefer_descriptive_audio_key),
false);
diff --git a/app/src/main/java/org/schabi/newpipe/util/Localization.java b/app/src/main/java/org/schabi/newpipe/util/Localization.java
index 1073afffd..49e27d108 100644
--- a/app/src/main/java/org/schabi/newpipe/util/Localization.java
+++ b/app/src/main/java/org/schabi/newpipe/util/Localization.java
@@ -153,9 +153,9 @@ public final class Localization {
case (int) ListExtractor.ITEM_COUNT_UNKNOWN:
return "";
case (int) ListExtractor.ITEM_COUNT_INFINITE:
- return context.getResources().getString(R.string.infinite_videos);
+ return context.getString(R.string.infinite_videos);
case (int) ListExtractor.ITEM_COUNT_MORE_THAN_100:
- return context.getResources().getString(R.string.more_than_100_videos);
+ return context.getString(R.string.more_than_100_videos);
default:
return getQuantity(context, R.plurals.videos, R.string.no_videos, streamCount,
localizeNumber(streamCount));
@@ -168,9 +168,9 @@ public final class Localization {
case (int) ListExtractor.ITEM_COUNT_UNKNOWN:
return "";
case (int) ListExtractor.ITEM_COUNT_INFINITE:
- return context.getResources().getString(R.string.infinite_videos_mini);
+ return context.getString(R.string.infinite_videos_mini);
case (int) ListExtractor.ITEM_COUNT_MORE_THAN_100:
- return context.getResources().getString(R.string.more_than_100_videos_mini);
+ return context.getString(R.string.more_than_100_videos_mini);
default:
return String.valueOf(streamCount);
}
@@ -190,14 +190,20 @@ public final class Localization {
final double value = (double) count;
if (count >= 1000000000) {
- return localizeNumber(round(value / 1000000000))
- + context.getString(R.string.short_billion);
+ final double shortenedValue = value / 1000000000;
+ final int scale = shortenedValue >= 100 ? 0 : 1;
+ return context.getString(R.string.short_billion,
+ localizeNumber(round(shortenedValue, scale)));
} else if (count >= 1000000) {
- return localizeNumber(round(value / 1000000))
- + context.getString(R.string.short_million);
+ final double shortenedValue = value / 1000000;
+ final int scale = shortenedValue >= 100 ? 0 : 1;
+ return context.getString(R.string.short_million,
+ localizeNumber(round(shortenedValue, scale)));
} else if (count >= 1000) {
- return localizeNumber(round(value / 1000))
- + context.getString(R.string.short_thousand);
+ final double shortenedValue = value / 1000;
+ final int scale = shortenedValue >= 100 ? 0 : 1;
+ return context.getString(R.string.short_thousand,
+ localizeNumber(round(shortenedValue, scale)));
} else {
return localizeNumber(value);
}
@@ -416,8 +422,8 @@ public final class Localization {
}
}
- private static double round(final double value) {
- return new BigDecimal(value).setScale(1, RoundingMode.HALF_UP).doubleValue();
+ private static double round(final double value, final int scale) {
+ return new BigDecimal(value).setScale(scale, RoundingMode.HALF_UP).doubleValue();
}
private static String getQuantity(@NonNull final Context context,
diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
index e1d296297..f702c5bd5 100644
--- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java
@@ -57,8 +57,10 @@ import org.schabi.newpipe.local.subscription.SubscriptionFragment;
import org.schabi.newpipe.local.subscription.SubscriptionsImportFragment;
import org.schabi.newpipe.player.PlayQueueActivity;
import org.schabi.newpipe.player.Player;
+import org.schabi.newpipe.player.PlayerIntentType;
import org.schabi.newpipe.player.PlayerService;
import org.schabi.newpipe.player.PlayerType;
+import org.schabi.newpipe.player.TimestampChangeData;
import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.helper.PlayerHolder;
import org.schabi.newpipe.player.playqueue.PlayQueue;
@@ -67,6 +69,7 @@ import org.schabi.newpipe.settings.SettingsActivity;
import org.schabi.newpipe.util.external_communication.ShareUtils;
import java.util.List;
+import java.util.Optional;
public final class NavigationHelper {
public static final String MAIN_FRAGMENT_TAG = "main_fragment_tag";
@@ -85,54 +88,32 @@ public final class NavigationHelper {
public static Intent getPlayerIntent(@NonNull final Context context,
@NonNull final Class targetClazz,
@Nullable final PlayQueue playQueue,
- final boolean resumePlayback) {
- final Intent intent = new Intent(context, targetClazz);
-
- if (playQueue != null) {
- final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class);
- if (cacheKey != null) {
- intent.putExtra(Player.PLAY_QUEUE_KEY, cacheKey);
- }
- }
- intent.putExtra(Player.PLAYER_TYPE, PlayerType.MAIN.valueForIntent());
- intent.putExtra(Player.RESUME_PLAYBACK, resumePlayback);
- intent.putExtra(PlayerService.SHOULD_START_FOREGROUND_EXTRA, true);
-
- return intent;
+ @NonNull final PlayerIntentType playerIntentType) {
+ final String cacheKey = Optional.ofNullable(playQueue)
+ .map(queue -> SerializedCache.getInstance().put(queue, PlayQueue.class))
+ .orElse(null);
+ return new Intent(context, targetClazz)
+ .putExtra(Player.PLAY_QUEUE_KEY, cacheKey)
+ .putExtra(Player.PLAYER_TYPE, PlayerType.MAIN)
+ .putExtra(PlayerService.SHOULD_START_FOREGROUND_EXTRA, true)
+ .putExtra(Player.PLAYER_INTENT_TYPE, playerIntentType);
}
@NonNull
- public static Intent getPlayerIntent(@NonNull final Context context,
- @NonNull final Class targetClazz,
- @Nullable final PlayQueue playQueue,
- final boolean resumePlayback,
- final boolean playWhenReady) {
- return getPlayerIntent(context, targetClazz, playQueue, resumePlayback)
- .putExtra(Player.PLAY_WHEN_READY, playWhenReady);
- }
-
- @NonNull
- public static Intent getPlayerEnqueueIntent(@NonNull final Context context,
- @NonNull final Class targetClazz,
- @Nullable final PlayQueue playQueue) {
- // when enqueueing `resumePlayback` is always `false` since:
- // - if there is a video already playing, the value of `resumePlayback` just doesn't make
- // any difference.
- // - if there is nothing already playing, it is useful for the enqueue action to have a
- // slightly different behaviour than the normal play action: the latter resumes playback,
- // the former doesn't. (note that enqueue can be triggered when nothing is playing only
- // by long pressing the video detail fragment, playlist or channel controls
- return getPlayerIntent(context, targetClazz, playQueue, false)
- .putExtra(Player.ENQUEUE, true);
+ public static Intent getPlayerTimestampIntent(@NonNull final Context context,
+ @NonNull final TimestampChangeData data) {
+ return new Intent(context, PlayerService.class)
+ .putExtra(Player.PLAYER_INTENT_TYPE, PlayerIntentType.TimestampChange)
+ .putExtra(Player.PLAYER_INTENT_DATA, data);
}
@NonNull
public static Intent getPlayerEnqueueNextIntent(@NonNull final Context context,
@NonNull final Class targetClazz,
@Nullable final PlayQueue playQueue) {
- // see comment in `getPlayerEnqueueIntent` as to why `resumePlayback` is false
- return getPlayerIntent(context, targetClazz, playQueue, false)
- .putExtra(Player.ENQUEUE_NEXT, true);
+ return getPlayerIntent(context, targetClazz, playQueue, PlayerIntentType.EnqueueNext)
+ // see comment in `getPlayerEnqueueIntent` as to why `resumePlayback` is false
+ .putExtra(Player.RESUME_PLAYBACK, false);
}
/* PLAY */
@@ -166,8 +147,10 @@ public final class NavigationHelper {
Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show();
- final Intent intent = getPlayerIntent(context, PlayerService.class, queue, resumePlayback);
- intent.putExtra(Player.PLAYER_TYPE, PlayerType.POPUP.valueForIntent());
+ final var intent = getPlayerIntent(context, PlayerService.class, queue,
+ PlayerIntentType.AllOthers)
+ .putExtra(Player.PLAYER_TYPE, PlayerType.POPUP)
+ .putExtra(Player.RESUME_PLAYBACK, resumePlayback);
ContextCompat.startForegroundService(context, intent);
}
@@ -177,8 +160,10 @@ public final class NavigationHelper {
Toast.makeText(context, R.string.background_player_playing_toast, Toast.LENGTH_SHORT)
.show();
- final Intent intent = getPlayerIntent(context, PlayerService.class, queue, resumePlayback);
- intent.putExtra(Player.PLAYER_TYPE, PlayerType.AUDIO.valueForIntent());
+ final Intent intent = getPlayerIntent(context, PlayerService.class, queue,
+ PlayerIntentType.AllOthers)
+ .putExtra(Player.PLAYER_TYPE, PlayerType.AUDIO)
+ .putExtra(Player.RESUME_PLAYBACK, resumePlayback);
ContextCompat.startForegroundService(context, intent);
}
@@ -191,9 +176,18 @@ public final class NavigationHelper {
}
Toast.makeText(context, R.string.enqueued, Toast.LENGTH_SHORT).show();
- final Intent intent = getPlayerEnqueueIntent(context, PlayerService.class, queue);
- intent.putExtra(Player.PLAYER_TYPE, playerType.valueForIntent());
+ // when enqueueing `resumePlayback` is always `false` since:
+ // - if there is a video already playing, the value of `resumePlayback` just doesn't make
+ // any difference.
+ // - if there is nothing already playing, it is useful for the enqueue action to have a
+ // slightly different behaviour than the normal play action: the latter resumes playback,
+ // the former doesn't. (note that enqueue can be triggered when nothing is playing only
+ // by long pressing the video detail fragment, playlist or channel controls
+ final Intent intent = getPlayerIntent(context, PlayerService.class, queue,
+ PlayerIntentType.Enqueue)
+ .putExtra(Player.RESUME_PLAYBACK, false)
+ .putExtra(Player.PLAYER_TYPE, playerType);
ContextCompat.startForegroundService(context, intent);
}
@@ -215,9 +209,8 @@ public final class NavigationHelper {
playerType = PlayerType.AUDIO;
}
Toast.makeText(context, R.string.enqueued_next, Toast.LENGTH_SHORT).show();
- final Intent intent = getPlayerEnqueueNextIntent(context, PlayerService.class, queue);
-
- intent.putExtra(Player.PLAYER_TYPE, playerType.valueForIntent());
+ final Intent intent = getPlayerEnqueueNextIntent(context, PlayerService.class, queue)
+ .putExtra(Player.PLAYER_TYPE, playerType);
ContextCompat.startForegroundService(context, intent);
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java b/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java
index 55193599e..969d787d7 100644
--- a/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java
@@ -9,12 +9,15 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
+import android.text.Html;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
+import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
+import org.schabi.newpipe.App;
import org.schabi.newpipe.R;
import org.schabi.newpipe.settings.NewPipeSettings;
@@ -87,9 +90,12 @@ public final class PermissionHelper {
&& ContextCompat.checkSelfPermission(activity,
Manifest.permission.POST_NOTIFICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- ActivityCompat.requestPermissions(activity,
- new String[] {Manifest.permission.POST_NOTIFICATIONS}, requestCode);
- return false;
+ if (!App.getApp().getNotificationsRequested()) {
+ ActivityCompat.requestPermissions(activity,
+ new String[]{Manifest.permission.POST_NOTIFICATIONS}, requestCode);
+ App.getApp().setNotificationsRequested();
+ return false;
+ }
}
return true;
}
@@ -113,14 +119,47 @@ public final class PermissionHelper {
@RequiresApi(api = Build.VERSION_CODES.M)
public static boolean checkSystemAlertWindowPermission(final Context context) {
if (!Settings.canDrawOverlays(context)) {
- final Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
- Uri.parse("package:" + context.getPackageName()));
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- context.startActivity(i);
- } catch (final ActivityNotFoundException ignored) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ final Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
+ Uri.parse("package:" + context.getPackageName()));
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ context.startActivity(i);
+ } catch (final ActivityNotFoundException ignored) {
+ }
+ return false;
+ // from Android R the ACTION_MANAGE_OVERLAY_PERMISSION will only point to the menu,
+ // so let’s add a dialog that points the user to the right setting.
+ } else {
+ final String appName = context.getApplicationInfo()
+ .loadLabel(context.getPackageManager()).toString();
+ final String title = context.getString(R.string.permission_display_over_apps);
+ final String permissionName =
+ context.getString(R.string.permission_display_over_apps_permission_name);
+ final String appNameItalic = "" + appName + "";
+ final String permissionNameItalic = "" + permissionName + "";
+ final String message =
+ context.getString(R.string.permission_display_over_apps_message,
+ appNameItalic,
+ permissionNameItalic
+ );
+ new AlertDialog.Builder(context)
+ .setTitle(title)
+ .setMessage(Html.fromHtml(message, Html.FROM_HTML_MODE_COMPACT))
+ .setPositiveButton("OK", (dialog, which) -> {
+ // we don’t need the package name here, since it won’t do anything on >R
+ final Intent intent =
+ new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
+ try {
+ context.startActivity(intent);
+ } catch (final ActivityNotFoundException ignored) {
+ }
+ })
+ .setCancelable(true)
+ .show();
+ return false;
}
- return false;
+
} else {
return true;
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/PlayButtonHelper.java b/app/src/main/java/org/schabi/newpipe/util/PlayButtonHelper.java
index 9727c8083..655ea7092 100644
--- a/app/src/main/java/org/schabi/newpipe/util/PlayButtonHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/PlayButtonHelper.java
@@ -50,6 +50,10 @@ public final class PlayButtonHelper {
});
// long click listener
+ playlistControlBinding.playlistCtrlPlayAllButton.setOnLongClickListener(view -> {
+ NavigationHelper.enqueueOnPlayer(activity, fragment.getPlayQueue(), PlayerType.MAIN);
+ return true;
+ });
playlistControlBinding.playlistCtrlPlayPopupButton.setOnLongClickListener(view -> {
NavigationHelper.enqueueOnPlayer(activity, fragment.getPlayQueue(), PlayerType.POPUP);
return true;
diff --git a/app/src/main/java/org/schabi/newpipe/util/SparseItemUtil.java b/app/src/main/java/org/schabi/newpipe/util/SparseItemUtil.java
index 6e9ea7a47..05f26f178 100644
--- a/app/src/main/java/org/schabi/newpipe/util/SparseItemUtil.java
+++ b/app/src/main/java/org/schabi/newpipe/util/SparseItemUtil.java
@@ -121,7 +121,7 @@ public final class SparseItemUtil {
callback.accept(result);
}, throwable -> ErrorUtil.createNotification(context,
new ErrorInfo(throwable, UserAction.REQUESTED_STREAM,
- "Loading stream info: " + url, serviceId)
+ "Loading stream info: " + url, serviceId, url)
));
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java
index ab74e0305..24a0f457f 100644
--- a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java
@@ -263,7 +263,7 @@ public final class ThemeHelper {
private static String getSelectedThemeKey(final Context context) {
final String themeKey = context.getString(R.string.theme_key);
- final String defaultTheme = context.getResources().getString(R.string.default_theme_value);
+ final String defaultTheme = context.getString(R.string.default_theme_value);
return PreferenceManager.getDefaultSharedPreferences(context)
.getString(themeKey, defaultTheme);
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/external_communication/ShareUtils.java b/app/src/main/java/org/schabi/newpipe/util/external_communication/ShareUtils.java
index 7524e5413..9fe351b4b 100644
--- a/app/src/main/java/org/schabi/newpipe/util/external_communication/ShareUtils.java
+++ b/app/src/main/java/org/schabi/newpipe/util/external_communication/ShareUtils.java
@@ -5,10 +5,9 @@ import static org.schabi.newpipe.MainActivity.DEBUG;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ClipboardManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
@@ -23,6 +22,7 @@ import androidx.core.content.FileProvider;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.R;
+import org.schabi.newpipe.RouterActivity;
import org.schabi.newpipe.extractor.Image;
import org.schabi.newpipe.util.image.ImageStrategy;
import org.schabi.newpipe.util.image.PicassoHelper;
@@ -62,8 +62,9 @@ public final class ShareUtils {
}
/**
- * Open the url with the system default browser. If no browser is set as default, falls back to
- * {@link #openAppChooser(Context, Intent, boolean)}.
+ * Open the url with the system default browser. If no browser is installed, falls back to
+ * {@link #openAppChooser(Context, Intent, boolean)} (for displaying that no apps are available
+ * to handle the action, or possible OEM-related edge cases).
*
* This function selects the package to open based on which apps respond to the {@code http://}
* schema alone, which should exclude special non-browser apps that are can handle the url (e.g.
@@ -77,44 +78,26 @@ public final class ShareUtils {
* @param url the url to browse
**/
public static void openUrlInBrowser(@NonNull final Context context, final String url) {
- // Resolve using a generic http://, so we are sure to get a browser and not e.g. the yt app.
+ // Target a generic http://, so we are sure to get a browser and not e.g. the yt app.
// Note that this requires the `http` schema to be added to `` in the manifest.
- final ResolveInfo defaultBrowserInfo;
final Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://"));
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- defaultBrowserInfo = context.getPackageManager().resolveActivity(browserIntent,
- PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY));
- } else {
- defaultBrowserInfo = context.getPackageManager().resolveActivity(browserIntent,
- PackageManager.MATCH_DEFAULT_ONLY);
- }
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url))
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- if (defaultBrowserInfo == null) {
- // No app installed to open a web URL, but it may be handled by other apps so try
- // opening a system chooser for the link in this case (it could be bypassed by the
- // system if there is only one app which can open the link or a default app associated
- // with the link domain on Android 12 and higher)
+ // See https://stackoverflow.com/a/58801285 and `setSelector` documentation
+ intent.setSelector(browserIntent);
+ try {
+ context.startActivity(intent);
+ } catch (final ActivityNotFoundException e) {
+ // No browser is available. This should, in the end, yield a nice AOSP error message
+ // indicating that no app is available to handle this action.
+ //
+ // Note: there are some situations where modified OEM ROMs have apps that appear
+ // to be browsers but are actually app choosers. If starting the Activity fails
+ // related to this, opening the system app chooser is still the correct behavior.
+ intent.setSelector(null);
openAppChooser(context, intent, true);
- return;
- }
-
- final String defaultBrowserPackage = defaultBrowserInfo.activityInfo.packageName;
-
- if (defaultBrowserPackage.equals("android")) {
- // No browser set as default (doesn't work on some devices)
- openAppChooser(context, intent, true);
- } else {
- try {
- intent.setPackage(defaultBrowserPackage);
- context.startActivity(intent);
- } catch (final ActivityNotFoundException e) {
- // Not a browser but an app chooser because of OEMs changes
- intent.setPackage(null);
- openAppChooser(context, intent, true);
- }
}
}
@@ -190,6 +173,18 @@ public final class ShareUtils {
chooserIntent.putExtra(Intent.EXTRA_TITLE, context.getString(R.string.open_with));
}
+ // Avoid opening in NewPipe
+ // (Implementation note: if the URL is one for which NewPipe itself
+ // is set as handler on Android >= 12, we actually remove the only eligible app
+ // for this link, and browsers will not be offered to the user. For that, use
+ // `openUrlInBrowser`.)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ chooserIntent.putExtra(
+ Intent.EXTRA_EXCLUDE_COMPONENTS,
+ new ComponentName[]{new ComponentName(context, RouterActivity.class)}
+ );
+ }
+
// Migrate any clip data and flags from the original intent.
final int permFlags = intent.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
diff --git a/app/src/main/java/org/schabi/newpipe/util/text/InternalUrlsHandler.java b/app/src/main/java/org/schabi/newpipe/util/text/InternalUrlsHandler.java
index 066515d6b..3288b4347 100644
--- a/app/src/main/java/org/schabi/newpipe/util/text/InternalUrlsHandler.java
+++ b/app/src/main/java/org/schabi/newpipe/util/text/InternalUrlsHandler.java
@@ -1,64 +1,27 @@
package org.schabi.newpipe.util.text;
import android.content.Context;
-import android.util.Log;
+import android.content.Intent;
+import androidx.core.content.ContextCompat;
import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
-
-import org.schabi.newpipe.MainActivity;
-import org.schabi.newpipe.R;
-import org.schabi.newpipe.error.ErrorPanelHelper;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
-import org.schabi.newpipe.extractor.stream.StreamInfo;
-import org.schabi.newpipe.player.playqueue.PlayQueue;
-import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
-import org.schabi.newpipe.util.ExtractorHelper;
+import org.schabi.newpipe.player.TimestampChangeData;
import org.schabi.newpipe.util.NavigationHelper;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
-import io.reactivex.rxjava3.core.Single;
-import io.reactivex.rxjava3.disposables.CompositeDisposable;
-import io.reactivex.rxjava3.schedulers.Schedulers;
-
public final class InternalUrlsHandler {
- private static final String TAG = InternalUrlsHandler.class.getSimpleName();
- private static final boolean DEBUG = MainActivity.DEBUG;
-
private static final Pattern AMPERSAND_TIMESTAMP_PATTERN = Pattern.compile("(.*)&t=(\\d+)");
- private static final Pattern HASHTAG_TIMESTAMP_PATTERN =
- Pattern.compile("(.*)#timestamp=(\\d+)");
private InternalUrlsHandler() {
}
- /**
- * Handle a YouTube timestamp comment URL in NewPipe.
- *
- * This method will check if the provided url is a YouTube comment description URL ({@code
- * https://www.youtube.com/watch?v=}video_id{@code #timestamp=}time_in_seconds). If yes, the
- * popup player will be opened when the user will click on the timestamp in the comment,
- * at the time and for the video indicated in the timestamp.
- *
- * @param disposables a field of the Activity/Fragment class that calls this method
- * @param context the context to use
- * @param url the URL to check if it can be handled
- * @return true if the URL can be handled by NewPipe, false if it cannot
- */
- public static boolean handleUrlCommentsTimestamp(@NonNull final CompositeDisposable
- disposables,
- final Context context,
- @NonNull final String url) {
- return handleUrl(context, url, HASHTAG_TIMESTAMP_PATTERN, disposables);
- }
-
/**
* Handle a YouTube timestamp description URL in NewPipe.
*
@@ -67,36 +30,13 @@ public final class InternalUrlsHandler {
* player will be opened when the user will click on the timestamp in the video description,
* at the time and for the video indicated in the timestamp.
*
- * @param disposables a field of the Activity/Fragment class that calls this method
* @param context the context to use
* @param url the URL to check if it can be handled
* @return true if the URL can be handled by NewPipe, false if it cannot
*/
- public static boolean handleUrlDescriptionTimestamp(@NonNull final CompositeDisposable
- disposables,
- final Context context,
+ public static boolean handleUrlDescriptionTimestamp(final Context context,
@NonNull final String url) {
- return handleUrl(context, url, AMPERSAND_TIMESTAMP_PATTERN, disposables);
- }
-
- /**
- * Handle an URL in NewPipe.
- *
- * This method will check if the provided url can be handled in NewPipe or not. If this is a
- * service URL with a timestamp, the popup player will be opened and true will be returned;
- * else, false will be returned.
- *
- * @param context the context to use
- * @param url the URL to check if it can be handled
- * @param pattern the pattern to use
- * @param disposables a field of the Activity/Fragment class that calls this method
- * @return true if the URL can be handled by NewPipe, false if it cannot
- */
- private static boolean handleUrl(final Context context,
- @NonNull final String url,
- @NonNull final Pattern pattern,
- @NonNull final CompositeDisposable disposables) {
- final Matcher matcher = pattern.matcher(url);
+ final Matcher matcher = AMPERSAND_TIMESTAMP_PATTERN.matcher(url);
if (!matcher.matches()) {
return false;
}
@@ -121,7 +61,7 @@ public final class InternalUrlsHandler {
}
if (linkType == StreamingService.LinkType.STREAM && seconds != -1) {
- return playOnPopup(context, matchedUrl, service, seconds, disposables);
+ return playOnPopup(context, matchedUrl, service, seconds);
} else {
NavigationHelper.openRouterActivity(context, matchedUrl);
return true;
@@ -135,15 +75,12 @@ public final class InternalUrlsHandler {
* @param url the URL of the content
* @param service the service of the content
* @param seconds the position in seconds at which the floating player will start
- * @param disposables disposables created by the method are added here and their lifecycle
- * should be handled by the calling class
* @return true if the playback of the content has successfully started or false if not
*/
public static boolean playOnPopup(final Context context,
final String url,
@NonNull final StreamingService service,
- final int seconds,
- @NonNull final CompositeDisposable disposables) {
+ final int seconds) {
final LinkHandlerFactory factory = service.getStreamLHFactory();
final String cleanUrl;
@@ -153,25 +90,14 @@ public final class InternalUrlsHandler {
return false;
}
- final Single single =
- ExtractorHelper.getStreamInfo(service.getServiceId(), cleanUrl, false);
- disposables.add(single.subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(info -> {
- final PlayQueue playQueue =
- new SinglePlayQueue(info, seconds * 1000L);
- NavigationHelper.playOnPopupPlayer(context, playQueue, false);
- }, throwable -> {
- if (DEBUG) {
- Log.e(TAG, "Could not play on popup: " + url, throwable);
- }
- new AlertDialog.Builder(context)
- .setTitle(R.string.player_stream_failure)
- .setMessage(
- ErrorPanelHelper.Companion.getExceptionDescription(throwable))
- .setPositiveButton(R.string.ok, null)
- .show();
- }));
+ final Intent intent = NavigationHelper.getPlayerTimestampIntent(context,
+ new TimestampChangeData(
+ service.getServiceId(),
+ cleanUrl,
+ seconds
+ ));
+ ContextCompat.startForegroundService(context, intent);
+
return true;
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/text/TextLinkifier.java b/app/src/main/java/org/schabi/newpipe/util/text/TextLinkifier.java
index 1419ac85a..4221da398 100644
--- a/app/src/main/java/org/schabi/newpipe/util/text/TextLinkifier.java
+++ b/app/src/main/java/org/schabi/newpipe/util/text/TextLinkifier.java
@@ -192,7 +192,7 @@ public final class TextLinkifier {
*
* Instead of using an {@link android.content.Intent#ACTION_VIEW} intent in the description of
* a content, this method will parse the {@link CharSequence} and replace all current web links
- * with {@link ShareUtils#openUrlInBrowser(Context, String, boolean)}.
+ * with {@link ShareUtils#openUrlInBrowser(Context, String)}.
*
*
*
@@ -240,7 +240,7 @@ public final class TextLinkifier {
for (final URLSpan span : urls) {
final String url = span.getURL();
final LongPressClickableSpan longPressClickableSpan =
- new UrlLongPressClickableSpan(context, disposables, url);
+ new UrlLongPressClickableSpan(context, url);
textBlockLinked.setSpan(longPressClickableSpan,
textBlockLinked.getSpanStart(span),
diff --git a/app/src/main/java/org/schabi/newpipe/util/text/TimestampLongPressClickableSpan.java b/app/src/main/java/org/schabi/newpipe/util/text/TimestampLongPressClickableSpan.java
index f5864794a..35a9fd996 100644
--- a/app/src/main/java/org/schabi/newpipe/util/text/TimestampLongPressClickableSpan.java
+++ b/app/src/main/java/org/schabi/newpipe/util/text/TimestampLongPressClickableSpan.java
@@ -46,7 +46,7 @@ final class TimestampLongPressClickableSpan extends LongPressClickableSpan {
@Override
public void onClick(@NonNull final View view) {
playOnPopup(context, relatedStreamUrl, relatedInfoService,
- timestampMatchDTO.seconds(), disposables);
+ timestampMatchDTO.seconds());
}
@Override
diff --git a/app/src/main/java/org/schabi/newpipe/util/text/UrlLongPressClickableSpan.java b/app/src/main/java/org/schabi/newpipe/util/text/UrlLongPressClickableSpan.java
index 61c1a546d..ec3cefc62 100644
--- a/app/src/main/java/org/schabi/newpipe/util/text/UrlLongPressClickableSpan.java
+++ b/app/src/main/java/org/schabi/newpipe/util/text/UrlLongPressClickableSpan.java
@@ -7,29 +7,22 @@ import androidx.annotation.NonNull;
import org.schabi.newpipe.util.external_communication.ShareUtils;
-import io.reactivex.rxjava3.disposables.CompositeDisposable;
-
final class UrlLongPressClickableSpan extends LongPressClickableSpan {
@NonNull
private final Context context;
@NonNull
- private final CompositeDisposable disposables;
- @NonNull
private final String url;
UrlLongPressClickableSpan(@NonNull final Context context,
- @NonNull final CompositeDisposable disposables,
@NonNull final String url) {
this.context = context;
- this.disposables = disposables;
this.url = url;
}
@Override
public void onClick(@NonNull final View view) {
- if (!InternalUrlsHandler.handleUrlDescriptionTimestamp(
- disposables, context, url)) {
+ if (!InternalUrlsHandler.handleUrlDescriptionTimestamp(context, url)) {
ShareUtils.openUrlInApp(context, url);
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java b/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java
index 175c81e46..7452fff09 100644
--- a/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java
+++ b/app/src/main/java/org/schabi/newpipe/views/ExpandableSurfaceView.java
@@ -35,12 +35,12 @@ public class ExpandableSurfaceView extends SurfaceView {
&& resizeMode != RESIZE_MODE_FIT
&& verticalVideo ? maxHeight : baseHeight;
- if (height == 0) {
+ if (width == 0 || height == 0) {
return;
}
final float viewAspectRatio = width / ((float) height);
- final float aspectDeformation = videoAspectRatio / viewAspectRatio - 1;
+ final float aspectDeformation = (videoAspectRatio / viewAspectRatio) - 1;
scaleX = 1.0f;
scaleY = 1.0f;
@@ -100,7 +100,7 @@ public class ExpandableSurfaceView extends SurfaceView {
}
public void setAspectRatio(final float aspectRatio) {
- if (videoAspectRatio == aspectRatio) {
+ if (videoAspectRatio == aspectRatio || aspectRatio == 0 || !Float.isFinite(aspectRatio)) {
return;
}
diff --git a/app/src/main/java/us/shandian/giga/get/DownloadMission.java b/app/src/main/java/us/shandian/giga/get/DownloadMission.java
index 04930b002..54340ce5d 100644
--- a/app/src/main/java/us/shandian/giga/get/DownloadMission.java
+++ b/app/src/main/java/us/shandian/giga/get/DownloadMission.java
@@ -661,7 +661,8 @@ public class DownloadMission extends Mission {
* @return {@code true}, if storage is invalid and cannot be used
*/
public boolean hasInvalidStorage() {
- return errCode == ERROR_PROGRESS_LOST || storage == null || !storage.existsAsFile();
+ // Don't consider ERROR_PROGRESS_LOST as invalid storage - it can be recovered
+ return storage == null || !storage.existsAsFile();
}
/**
diff --git a/app/src/main/java/us/shandian/giga/get/DownloadRunnableFallback.java b/app/src/main/java/us/shandian/giga/get/DownloadRunnableFallback.java
index eed5db463..1d2483e79 100644
--- a/app/src/main/java/us/shandian/giga/get/DownloadRunnableFallback.java
+++ b/app/src/main/java/us/shandian/giga/get/DownloadRunnableFallback.java
@@ -85,6 +85,7 @@ public class DownloadRunnableFallback extends Thread {
if (mMission.unknownLength || mConn.getResponseCode() == 200) {
// restart amount of bytes downloaded
mMission.done = mMission.offsets[mMission.current] - mMission.offsets[0];
+ start = 0; // reset position to avoid writing at wrong offset
}
mF = mMission.storage.getStream();
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/OggFromWebmDemuxer.java b/app/src/main/java/us/shandian/giga/postprocessing/OggFromWebmDemuxer.java
index dc46ced5d..badb5f7ed 100644
--- a/app/src/main/java/us/shandian/giga/postprocessing/OggFromWebmDemuxer.java
+++ b/app/src/main/java/us/shandian/giga/postprocessing/OggFromWebmDemuxer.java
@@ -34,7 +34,7 @@ class OggFromWebmDemuxer extends Postprocessing {
@Override
int process(SharpStream out, @NonNull SharpStream... sources) throws IOException {
- OggFromWebMWriter demuxer = new OggFromWebMWriter(sources[0], out);
+ OggFromWebMWriter demuxer = new OggFromWebMWriter(sources[0], out, streamInfo);
demuxer.parseSource();
demuxer.selectTrack(0);
demuxer.build();
diff --git a/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java b/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
index 7f5c85d27..1c9143252 100644
--- a/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
+++ b/app/src/main/java/us/shandian/giga/postprocessing/Postprocessing.java
@@ -4,6 +4,7 @@ import android.util.Log;
import androidx.annotation.NonNull;
+import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.streams.io.SharpStream;
import java.io.File;
@@ -30,7 +31,8 @@ public abstract class Postprocessing implements Serializable {
public transient static final String ALGORITHM_M4A_NO_DASH = "mp4D-m4a";
public transient static final String ALGORITHM_OGG_FROM_WEBM_DEMUXER = "webm-ogg-d";
- public static Postprocessing getAlgorithm(@NonNull String algorithmName, String[] args) {
+ public static Postprocessing getAlgorithm(@NonNull String algorithmName, String[] args,
+ StreamInfo streamInfo) {
Postprocessing instance;
switch (algorithmName) {
@@ -56,6 +58,7 @@ public abstract class Postprocessing implements Serializable {
}
instance.args = args;
+ instance.streamInfo = streamInfo;
return instance;
}
@@ -75,8 +78,8 @@ public abstract class Postprocessing implements Serializable {
*/
private final String name;
-
private String[] args;
+ protected StreamInfo streamInfo;
private transient DownloadMission mission;
diff --git a/app/src/main/java/us/shandian/giga/service/DownloadManager.java b/app/src/main/java/us/shandian/giga/service/DownloadManager.java
index 9b90fa14b..7a2055aaa 100644
--- a/app/src/main/java/us/shandian/giga/service/DownloadManager.java
+++ b/app/src/main/java/us/shandian/giga/service/DownloadManager.java
@@ -24,6 +24,8 @@ import org.schabi.newpipe.streams.io.StoredFileHelper;
import us.shandian.giga.util.Utility;
import static org.schabi.newpipe.BuildConfig.DEBUG;
+import static us.shandian.giga.get.DownloadMission.ERROR_NOTHING;
+import static us.shandian.giga.get.DownloadMission.ERROR_PROGRESS_LOST;
public class DownloadManager {
private static final String TAG = DownloadManager.class.getSimpleName();
@@ -149,12 +151,31 @@ public class DownloadManager {
if (sub.getName().equals(".tmp")) continue;
DownloadMission mis = Utility.readFromFile(sub);
- if (mis == null || mis.isFinished() || mis.hasInvalidStorage()) {
+ if (mis == null) {
//noinspection ResultOfMethodCallIgnored
sub.delete();
continue;
}
+ // DON'T delete missions that are truly finished - let them be moved to finished list
+ if (mis.isFinished()) {
+ // Move to finished missions instead of deleting
+ setFinished(mis);
+ //noinspection ResultOfMethodCallIgnored
+ sub.delete();
+ continue;
+ }
+
+ // DON'T delete missions with storage issues - try to recover them
+ if (mis.hasInvalidStorage() && mis.errCode != ERROR_PROGRESS_LOST) {
+ // Only delete if it's truly unrecoverable (not just progress lost)
+ if (mis.storage == null) {
+ //noinspection ResultOfMethodCallIgnored
+ sub.delete();
+ continue;
+ }
+ }
+
mis.threads = new Thread[0];
boolean exists;
@@ -163,16 +184,13 @@ public class DownloadManager {
exists = !mis.storage.isInvalid() && mis.storage.existsAsFile();
} catch (Exception ex) {
Log.e(TAG, "Failed to load the file source of " + mis.storage.toString(), ex);
- mis.storage.invalidate();
+ // Don't invalidate storage immediately - try to recover first
exists = false;
}
if (mis.isPsRunning()) {
if (mis.psAlgorithm.worksOnSameFile) {
// Incomplete post-processing results in a corrupted download file
- // because the selected algorithm works on the same file to save space.
- // the file will be deleted if the storage API
- // is Java IO (avoid showing the "Save as..." dialog)
if (exists && mis.storage.isDirect() && !mis.storage.delete())
Log.w(TAG, "Unable to delete incomplete download file: " + sub.getPath());
}
@@ -181,10 +199,11 @@ public class DownloadManager {
mis.errCode = DownloadMission.ERROR_POSTPROCESSING_STOPPED;
} else if (!exists) {
tryRecover(mis);
-
- // the progress is lost, reset mission state
- if (mis.isInitialized())
- mis.resetState(true, true, DownloadMission.ERROR_PROGRESS_LOST);
+ // Keep the mission even if recovery fails - don't reset to ERROR_PROGRESS_LOST
+ // This allows user to see the failed download and potentially retry
+ if (mis.isInitialized() && mis.errCode == ERROR_NOTHING) {
+ mis.resetState(true, true, ERROR_PROGRESS_LOST);
+ }
}
if (mis.psAlgorithm != null) {
@@ -265,7 +284,7 @@ public class DownloadManager {
}
}
- public void deleteMission(Mission mission) {
+ public void deleteMission(Mission mission, boolean alsoDeleteFile) {
synchronized (this) {
if (mission instanceof DownloadMission) {
mMissionsPending.remove(mission);
@@ -274,7 +293,9 @@ public class DownloadManager {
mFinishedMissionStore.deleteMission(mission);
}
- mission.delete();
+ if (alsoDeleteFile) {
+ mission.delete();
+ }
}
}
@@ -446,7 +467,7 @@ public class DownloadManager {
continue;
resumeMission(mission);
- if (mission.errCode != DownloadMission.ERROR_NOTHING) continue;
+ if (mission.errCode != ERROR_NOTHING) continue;
if (mPrefQueueLimit) return true;
flag = true;
@@ -510,6 +531,15 @@ public class DownloadManager {
}
}
+ public boolean canRecoverMission(DownloadMission mission) {
+ if (mission == null) return false;
+
+ // Can recover missions with progress lost or storage issues
+ return mission.errCode == ERROR_PROGRESS_LOST ||
+ mission.storage == null ||
+ !mission.storage.existsAsFile();
+ }
+
public MissionState checkForExistingMission(StoredFileHelper storage) {
synchronized (this) {
DownloadMission pending = getPendingMission(storage);
@@ -582,8 +612,13 @@ public class DownloadManager {
ArrayList finished = new ArrayList<>(mMissionsFinished);
List remove = new ArrayList<>(hidden);
- // hide missions (if required)
- remove.removeIf(mission -> pending.remove(mission) || finished.remove(mission));
+ // Don't hide recoverable missions
+ remove.removeIf(mission -> {
+ if (mission instanceof DownloadMission dm && canRecoverMission(dm)) {
+ return false; // Don't remove recoverable missions
+ }
+ return pending.remove(mission) || finished.remove(mission);
+ });
int fakeTotal = pending.size();
if (fakeTotal > 0) fakeTotal++;
diff --git a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java
index 45211211f..76da18b2d 100755
--- a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java
+++ b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java
@@ -40,6 +40,7 @@ import androidx.preference.PreferenceManager;
import org.schabi.newpipe.R;
import org.schabi.newpipe.download.DownloadActivity;
+import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.helper.LockManager;
import org.schabi.newpipe.streams.io.StoredDirectoryHelper;
import org.schabi.newpipe.streams.io.StoredFileHelper;
@@ -74,12 +75,12 @@ public class DownloadManagerService extends Service {
private static final String EXTRA_THREADS = "DownloadManagerService.extra.threads";
private static final String EXTRA_POSTPROCESSING_NAME = "DownloadManagerService.extra.postprocessingName";
private static final String EXTRA_POSTPROCESSING_ARGS = "DownloadManagerService.extra.postprocessingArgs";
- private static final String EXTRA_SOURCE = "DownloadManagerService.extra.source";
private static final String EXTRA_NEAR_LENGTH = "DownloadManagerService.extra.nearLength";
private static final String EXTRA_PATH = "DownloadManagerService.extra.storagePath";
private static final String EXTRA_PARENT_PATH = "DownloadManagerService.extra.storageParentPath";
private static final String EXTRA_STORAGE_TAG = "DownloadManagerService.extra.storageTag";
private static final String EXTRA_RECOVERY_INFO = "DownloadManagerService.extra.recoveryInfo";
+ private static final String EXTRA_STREAM_INFO = "DownloadManagerService.extra.streamInfo";
private static final String ACTION_RESET_DOWNLOAD_FINISHED = APPLICATION_ID + ".reset_download_finished";
private static final String ACTION_OPEN_DOWNLOADS_FINISHED = APPLICATION_ID + ".open_downloads_finished";
@@ -353,13 +354,13 @@ public class DownloadManagerService extends Service {
* @param kind type of file (a: audio v: video s: subtitle ?: file-extension defined)
* @param threads the number of threads maximal used to download chunks of the file.
* @param psName the name of the required post-processing algorithm, or {@code null} to ignore.
- * @param source source url of the resource
+ * @param streamInfo stream metadata that may be written into the downloaded file.
* @param psArgs the arguments for the post-processing algorithm.
* @param nearLength the approximated final length of the file
* @param recoveryInfo array of MissionRecoveryInfo, in case is required recover the download
*/
public static void startMission(Context context, String[] urls, StoredFileHelper storage,
- char kind, int threads, String source, String psName,
+ char kind, int threads, StreamInfo streamInfo, String psName,
String[] psArgs, long nearLength,
ArrayList recoveryInfo) {
final Intent intent = new Intent(context, DownloadManagerService.class)
@@ -367,14 +368,14 @@ public class DownloadManagerService extends Service {
.putExtra(EXTRA_URLS, urls)
.putExtra(EXTRA_KIND, kind)
.putExtra(EXTRA_THREADS, threads)
- .putExtra(EXTRA_SOURCE, source)
.putExtra(EXTRA_POSTPROCESSING_NAME, psName)
.putExtra(EXTRA_POSTPROCESSING_ARGS, psArgs)
.putExtra(EXTRA_NEAR_LENGTH, nearLength)
.putExtra(EXTRA_RECOVERY_INFO, recoveryInfo)
.putExtra(EXTRA_PARENT_PATH, storage.getParentUri())
.putExtra(EXTRA_PATH, storage.getUri())
- .putExtra(EXTRA_STORAGE_TAG, storage.getTag());
+ .putExtra(EXTRA_STORAGE_TAG, storage.getTag())
+ .putExtra(EXTRA_STREAM_INFO, streamInfo);
context.startService(intent);
}
@@ -387,9 +388,9 @@ public class DownloadManagerService extends Service {
char kind = intent.getCharExtra(EXTRA_KIND, '?');
String psName = intent.getStringExtra(EXTRA_POSTPROCESSING_NAME);
String[] psArgs = intent.getStringArrayExtra(EXTRA_POSTPROCESSING_ARGS);
- String source = intent.getStringExtra(EXTRA_SOURCE);
long nearLength = intent.getLongExtra(EXTRA_NEAR_LENGTH, 0);
String tag = intent.getStringExtra(EXTRA_STORAGE_TAG);
+ StreamInfo streamInfo = (StreamInfo)intent.getSerializableExtra(EXTRA_STREAM_INFO);
final var recovery = IntentCompat.getParcelableArrayListExtra(intent, EXTRA_RECOVERY_INFO,
MissionRecoveryInfo.class);
Objects.requireNonNull(recovery);
@@ -405,11 +406,11 @@ public class DownloadManagerService extends Service {
if (psName == null)
ps = null;
else
- ps = Postprocessing.getAlgorithm(psName, psArgs);
+ ps = Postprocessing.getAlgorithm(psName, psArgs, streamInfo);
final DownloadMission mission = new DownloadMission(urls, storage, kind, ps);
mission.threadCount = threads;
- mission.source = source;
+ mission.source = streamInfo.getUrl();
mission.nearLength = nearLength;
mission.recoveryInfo = recovery.toArray(new MissionRecoveryInfo[0]);
diff --git a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java
index 9722a9a1f..54ae2cfa4 100644
--- a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java
+++ b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java
@@ -2,6 +2,7 @@ package us.shandian.giga.ui.adapter;
import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
+import static android.content.Intent.createChooser;
import static us.shandian.giga.get.DownloadMission.ERROR_CONNECT_HOST;
import static us.shandian.giga.get.DownloadMission.ERROR_FILE_CREATION;
import static us.shandian.giga.get.DownloadMission.ERROR_HTTP_NO_CONTENT;
@@ -349,11 +350,15 @@ public class MissionAdapter extends Adapter implements Handler.Callb
if (BuildConfig.DEBUG)
Log.v(TAG, "Mime: " + mimeType + " package: " + BuildConfig.APPLICATION_ID + ".provider");
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(resolveShareableUri(mission), mimeType);
- intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
- intent.addFlags(FLAG_GRANT_PREFIX_URI_PERMISSION);
- ShareUtils.openIntentInApp(mContext, intent);
+ Intent viewIntent = new Intent(Intent.ACTION_VIEW);
+ viewIntent.setDataAndType(resolveShareableUri(mission), mimeType);
+ viewIntent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
+ viewIntent.addFlags(FLAG_GRANT_PREFIX_URI_PERMISSION);
+
+ Intent chooserIntent = createChooser(viewIntent, null);
+ chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | FLAG_GRANT_READ_URI_PERMISSION);
+
+ ShareUtils.openIntentInApp(mContext, chooserIntent);
}
private void shareFile(Mission mission) {
@@ -364,8 +369,7 @@ public class MissionAdapter extends Adapter implements Handler.Callb
shareIntent.putExtra(Intent.EXTRA_STREAM, resolveShareableUri(mission));
shareIntent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
- final Intent intent = new Intent(Intent.ACTION_CHOOSER);
- intent.putExtra(Intent.EXTRA_INTENT, shareIntent);
+ final Intent intent = createChooser(shareIntent, null);
// unneeded to set a title to the chooser on Android P and higher because the system
// ignores this title on these versions
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
@@ -563,16 +567,16 @@ public class MissionAdapter extends Adapter implements Handler.Callb
}
request.append("]");
- String service;
+ Integer service;
try {
- service = NewPipe.getServiceByUrl(mission.source).getServiceInfo().getName();
+ service = NewPipe.getServiceByUrl(mission.source).getServiceId();
} catch (Exception e) {
- service = ErrorInfo.SERVICE_NONE;
+ service = null;
}
ErrorUtil.createNotification(mContext,
new ErrorInfo(ErrorInfo.Companion.throwableToStringList(mission.errObject), action,
- service, request.toString(), reason));
+ request.toString(), service, reason));
}
public void clearFinishedDownloads(boolean delete) {
@@ -614,7 +618,7 @@ public class MissionAdapter extends Adapter implements Handler.Callb
while (i.hasNext()) {
Mission mission = i.next();
if (mission != null) {
- mDownloadManager.deleteMission(mission);
+ mDownloadManager.deleteMission(mission, true);
mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mission.storage.getUri()));
}
i.remove();
@@ -667,7 +671,14 @@ public class MissionAdapter extends Adapter implements Handler.Callb
shareFile(h.item.mission);
return true;
case R.id.delete:
- mDeleter.append(h.item.mission);
+ // delete the entry and the file
+ mDeleter.append(h.item.mission, true);
+ applyChanges();
+ checkMasterButtonsVisibility();
+ return true;
+ case R.id.delete_entry:
+ // just delete the entry
+ mDeleter.append(h.item.mission, false);
applyChanges();
checkMasterButtonsVisibility();
return true;
@@ -676,7 +687,7 @@ public class MissionAdapter extends Adapter implements Handler.Callb
final StoredFileHelper storage = h.item.mission.storage;
if (!storage.existsAsFile()) {
Toast.makeText(mContext, R.string.missing_file, Toast.LENGTH_SHORT).show();
- mDeleter.append(h.item.mission);
+ mDeleter.append(h.item.mission, true);
applyChanges();
return true;
}
diff --git a/app/src/main/java/us/shandian/giga/ui/common/Deleter.java b/app/src/main/java/us/shandian/giga/ui/common/Deleter.java
index 1902076d6..0f285fd74 100644
--- a/app/src/main/java/us/shandian/giga/ui/common/Deleter.java
+++ b/app/src/main/java/us/shandian/giga/ui/common/Deleter.java
@@ -13,7 +13,9 @@ import com.google.android.material.snackbar.Snackbar;
import org.schabi.newpipe.R;
import java.util.ArrayList;
+import java.util.Optional;
+import kotlin.Pair;
import us.shandian.giga.get.FinishedMission;
import us.shandian.giga.get.Mission;
import us.shandian.giga.service.DownloadManager;
@@ -30,7 +32,8 @@ public class Deleter {
private static final int DELAY_RESUME = 400;// ms
private Snackbar snackbar;
- private ArrayList items;
+ // list of missions to be deleted, and whether to also delete the corresponding file
+ private ArrayList> items;
private boolean running = true;
private final Context mContext;
@@ -51,7 +54,7 @@ public class Deleter {
items = new ArrayList<>(2);
}
- public void append(Mission item) {
+ public void append(Mission item, boolean alsoDeleteFile) {
/* If a mission is removed from the list while the Snackbar for a previously
* removed item is still showing, commit the action for the previous item
* immediately. This prevents Snackbars from stacking up in reverse order.
@@ -60,13 +63,13 @@ public class Deleter {
commit();
mIterator.hide(item);
- items.add(0, item);
+ items.add(0, new Pair<>(item, alsoDeleteFile));
show();
}
private void forget() {
- mIterator.unHide(items.remove(0));
+ mIterator.unHide(items.remove(0).getFirst());
mAdapter.applyChanges();
show();
@@ -84,7 +87,19 @@ public class Deleter {
private void next() {
if (items.size() < 1) return;
- String msg = mContext.getString(R.string.file_deleted).concat(":\n").concat(items.get(0).storage.getName());
+ final Optional fileToBeDeleted = items.stream()
+ .filter(Pair::getSecond)
+ .map(p -> p.getFirst().storage.getName())
+ .findFirst();
+
+ String msg;
+ if (fileToBeDeleted.isPresent()) {
+ msg = mContext.getString(R.string.file_deleted)
+ .concat(":\n")
+ .concat(fileToBeDeleted.get());
+ } else {
+ msg = mContext.getString(R.string.entry_deleted);
+ }
snackbar = Snackbar.make(mView, msg, Snackbar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.undo, s -> forget());
@@ -98,11 +113,13 @@ public class Deleter {
if (items.size() < 1) return;
while (items.size() > 0) {
- Mission mission = items.remove(0);
+ Pair missionAndAlsoDeleteFile = items.remove(0);
+ Mission mission = missionAndAlsoDeleteFile.getFirst();
+ boolean alsoDeleteFile = missionAndAlsoDeleteFile.getSecond();
if (mission.deleted) continue;
mIterator.unHide(mission);
- mDownloadManager.deleteMission(mission);
+ mDownloadManager.deleteMission(mission, alsoDeleteFile);
if (mission instanceof FinishedMission) {
mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mission.storage.getUri()));
@@ -137,7 +154,11 @@ public class Deleter {
pause();
- for (Mission mission : items) mDownloadManager.deleteMission(mission);
+ for (Pair missionAndAlsoDeleteFile : items) {
+ Mission mission = missionAndAlsoDeleteFile.getFirst();
+ boolean alsoDeleteFile = missionAndAlsoDeleteFile.getSecond();
+ mDownloadManager.deleteMission(mission, alsoDeleteFile);
+ }
items = null;
}
}
diff --git a/app/src/main/res/layout/player.xml b/app/src/main/res/layout/player.xml
index 99b514bb0..a6a0884c7 100644
--- a/app/src/main/res/layout/player.xml
+++ b/app/src/main/res/layout/player.xml
@@ -109,71 +109,89 @@
android:layout_marginEnd="8dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
+ android:contentDescription="@string/close"
android:focusable="true"
android:padding="@dimen/player_main_buttons_padding"
android:scaleType="fitXY"
android:src="@drawable/ic_close"
android:visibility="gone"
app:tint="@color/white"
- android:contentDescription="@string/close"
tools:ignore="RtlHardcoded" />
+ android:orientation="horizontal">
-
+ android:layout_marginTop="6dp"
+ android:layout_marginEnd="8dp"
+ android:layout_weight="1"
+ android:gravity="top"
+ android:orientation="vertical"
+ tools:ignore="NestedWeights,RtlHardcoded">
-
+
+
+
+
+
+
+ android:layout_weight="1">
+
+
+
+
-
-
@@ -368,11 +386,11 @@
android:layout_height="40dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
+ android:contentDescription="@string/toggle_fullscreen"
android:focusable="true"
android:padding="@dimen/player_main_buttons_padding"
android:scaleType="fitCenter"
android:src="@drawable/ic_fullscreen"
- android:contentDescription="@string/toggle_fullscreen"
android:visibility="gone"
app:tint="@color/white"
tools:ignore="RtlHardcoded"
@@ -492,13 +510,13 @@
android:layout_marginStart="4dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
+ android:contentDescription="@string/toggle_screen_orientation"
android:focusable="true"
android:nextFocusUp="@id/playbackSeekBar"
android:padding="@dimen/player_main_buttons_padding"
android:scaleType="fitCenter"
android:src="@drawable/ic_fullscreen"
android:visibility="gone"
- android:contentDescription="@string/toggle_screen_orientation"
app:tint="@color/white"
tools:ignore="RtlHardcoded"
tools:visibility="visible" />
@@ -520,10 +538,10 @@
android:layout_weight="1"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
+ android:contentDescription="@string/previous_stream"
android:focusable="true"
android:scaleType="fitCenter"
android:src="@drawable/ic_previous"
- android:contentDescription="@string/previous_stream"
app:tint="@color/white" />
@@ -533,9 +551,9 @@
android:layout_height="60dp"
android:layout_weight="1"
android:background="?attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/pause"
android:scaleType="fitCenter"
android:src="@drawable/ic_pause"
- android:contentDescription="@string/pause"
app:tint="@color/white" />
@@ -596,12 +614,12 @@
android:layout_marginLeft="40dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
+ android:contentDescription="@string/notification_action_repeat"
android:focusable="true"
android:padding="10dp"
android:scaleType="fitXY"
android:src="@drawable/exo_controls_repeat_off"
android:tint="?attr/colorAccent"
- android:contentDescription="@string/notification_action_repeat"
tools:ignore="RtlHardcoded" />
+ android:title="@string/delete_file" />
+
+
- الملفات المحملة
لا يوجد مثل هذا الملف/مصدر المحتوى
الأكثر إعجابًا
- بليون
تعذر تحميل موجز \'%s\'.
؟
التحقق من وجود تحديثات
مثيلات خوادم پيرتيوب
+100 فيديو
- ألف
مثيل الخادم موجود بالفعل
طلب تأكيد قبل مسح قائمة الانتظار
المشتركون
@@ -643,13 +641,11 @@
الصوت : %s
خطوة
حل
- %s يقدم هذا السبب:
الدفق المحدد غير مدعوم من قبل المشغلون الخارجيون
عن تطبيق نيوپايپ
تسريع إلى الأمام/-ترجيع وقت البحث
تم رفضها من قبل النظام
ليس هناك تعليقات
- مليون
جاري التحقق من وجود تحديثات…
المحتوى
اسأل عن مكان التنزيل
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index 7e002d88a..895314ad5 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -116,9 +116,6 @@
لا شيء هنا سوى الصراصير
الصوت
إعادة المحاولة
- ألف
- مليون
- بليون
ليس هناك مشترِكون
- %s مشارك
@@ -652,7 +649,6 @@
تمكين تحديد نص في الوصف
يمكنك الآن تحديد نص داخل الوصف. لاحظ أن الصفحة قد تومض وقد لا تكون الروابط قابلة للنقر أثناء وضع التحديد.
فتح الموقع
- %s يقدم هذا السبب:
تم إنهاء الحساب
لا يوفر وضع التغذية السريعة مزيدًا من المعلومات حول هذا الموضوع.
حساب منشئ المحتوى قد تم إنهائه.
@@ -890,4 +886,24 @@
البحث %1$s (%2$s)
تمت إزالة صفحة أفضل 50 من SoundCloud
أوقفت SoundCloud صفحة أفضل 50 الأصلية. تمت إزالة علامة التبويب المقابلة من صفحتك الرئيسية.
+ تمت إزالة تريندات YouTube المجمعة
+ أوقف YouTube صفحة الترند المدمجة اعتبارًا من 21 يوليو 2025. استبدلت NewPipe صفحة الموضوعات المتداولة الافتراضية بصفحة الموضوعات المتداولة الشائعة مع البث المباشر المتداول.\n\nيمكنك أيضًا تحديد صفحات رائجة مختلفة في \"الإعدادات > المحتوى > محتوى الصفحة الرئيسية\".
+ توجهات الألعاب
+ توجهات البث الصوتي
+ الأفلام والعروض الأكثر رواجاً
+ الموسيقى الرائجة
+ %s الف
+ %s مليون
+ %sمليار
+ لاستخدام المشغل المنبثق، يرجى تحديد %1$s في قائمة إعدادات اندرويد التالية وتمكين %2$s.
+ “السماح بالعرض فوق التطبيقات الاخرى”
+ حذف ملف
+ حذف المدخلات
+ تم إنهاء الحساب\n\n%1$s يقدم هذا السبب: %2$s
+ تم حذف المدخلات
+ تم تلقي خطأ HTTP 403 من الخادم أثناء التشغيل، ويرجح أن يكون السبب هو انتهاء صلاحية عنوان URL للبث أو حظر عنوان IP
+ حدث خطأ HTTP %1$s من الخادم أثناء التشغيل
+ تم تلقي خطأ HTTP 403 من الخادم أثناء التشغيل، ويرجح أن يكون السبب هو حظر عنوان IP أو مشكلات في إزالة التعتيم عن عنوان URL للبث
+ رفض %1$s تقديم البيانات، وطلب تسجيل الدخول للتأكد من أن الطالب ليس روبوتًا.\n\nربما تم حظر عنوان IP الخاص بك مؤقتًا من قبل %1$s، يمكنك الانتظار بعض الوقت أو التبديل إلى عنوان IP مختلف (على سبيل المثال عن طريق تشغيل/إيقاف تشغيل VPN، أو التبديل من WiFi إلى بيانات الهاتف المحمول).
+ هذا المحتوى غير متاح للبلد المحدد حاليًا.\n\nقم بتغيير اختيارك من ”الإعدادات > المحتوى > البلد الافتراضي للمحتوى“.
diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml
index 682dda98f..689cf4937 100644
--- a/app/src/main/res/values-az/strings.xml
+++ b/app/src/main/res/values-az/strings.xml
@@ -192,10 +192,10 @@
Sil
Hələ ki, kanal abunəliyi yoxdur
Kanal seç
- Kanal Səhifəsi
+ Kanal səhifəsi
Standart Bölmə
- Kənar Səhifə
- Boş Səhifə
+ Kənar səhifə
+ Boş səhifə
Əsas səhifədə hansı tablar göstərilir
Əsas səhifə məzmunu
Yeni versiya mövcud olduqda tətbiq yeniləməsini xatırlatmaq üçün bildiriş göstər
@@ -295,11 +295,8 @@
Nə baş verdi:
Yükləyənin avatar miniatürü
Bəyən
- Bəyənmə
+ Bəyənməmə
Yenidən sıralamaq üçün sürüklə
- min
- Mln
- Mlrd
Xidməti dəyiş, hazırda seçilmiş:
Abunəçi yoxdur
Baxış yoxdur
@@ -504,7 +501,6 @@
Endirmə növbəsini məhdudlaşdır
Eyni vaxtda ancaq bir endirmə həyata keçiriləcək
Hesab ləğv edildi
- %s bu səbəbi təmin edir:
Yükləmə başladı
Açıqlamadakı mətni seçməyi qeyri-aktiv et
Kateqoriya
@@ -589,7 +585,7 @@
Serveri təsdiqləmək mümkün olmadı
%s-də bəyəndiyiniz serverləri tapın
Video \"Təfsilatlar\" səhifəsində fon və ya ani görüntü düyməsin basarkən ipucu göstər
- Oynadıcı titr mətn miqyasını və arxa fon üslublarını dəyişdir. Effektiv olması üçün tətbiqi yenidən başlatmaq tələb olunur
+ Oynadıcı titr mətn miqyasını və arxa plan üslublarını dəyişdir. Effektiv olması üçün tətbiqi yenidən başlatmaq tələb olunur
Xəta baş verdi: %1$s
Fayl mövcud deyil, yaxud oxumaq və ya yazmaq icazəsi yoxdur
Veb saytı təhlil etmək alınmadı
@@ -807,4 +803,29 @@
Axın qrupu seçin
Hələ heç bir axın qrupu yaradılmayıb
Kanal qrupu səhifəsi
+ %1$s axtar
+ %1$s (%2$s) axtar
+ Bəyənmə
+ SoundCloud Top 50 səhifəsi silindi
+ SoundCloud ilk Ən yaxşı 50 siyahısın ləğv etdi. Uyğun səhifə əsas səhifənizdən silindi.
+ %sMin
+ %sMln
+ %sMlrd
+ YouTube birləşmiş trend silindi
+ YouTube 21 iyul 2025-ci il tarixindən birləşmiş trend səhifəsini ləğv etdi. NewPipe ilkin trend səhifəsini trend olan canlı yayımlarla əvəz etdi. \n\nHəmçinin \"Tənzimləmələr > Məzmun > Əsas səhifə məzmunu\" bölməsində müxtəlif trendli səhifələri seçə bilərsiniz.
+ Trenddə olan Oyun
+ Trenddə olan podkastlar
+ Trend film və tamaşalar
+ Trenddə olan musiqilər
+ Ani oynadıcı istifadə etmək üçün lütfən, aşağıdakı Android tənzimləmələr menyusunda %1$s seçin və %2$s-ı aktivləşdirin.
+ \"Digər tətbiqlər üzərində göstərməyə icazə verin\"
+ Faylı sil
+ Girişi silin
+ Giriş silindi
+ Hesab ləğv edilib\n\n %1$s bu səbəbi təmin edir: %2$s
+ Oynadarkən serverdən alınan HTTP xətası 403, çox güman ki, yayım URL-si müddətinin bitməsi və ya IP qadağası ilə bağlıdır
+ HTTP xətası %1$s oynadarkən serverdən alındı
+ HTTP xətası 403 oynadarkən serverdən alındı, ehtimal ki, IP qadağası və ya yayım URL-nin deobfuscation problemləri ilə bağlıdır
+ %1$s sorğuçunun bot olmadığını təsdiqləmək üçün giriş tələb edərək data təmin etməkdən imtina etdi.\n\nIP-niz %1$s tərəfindən müvəqqəti şəkildə qadağan oluna bilər, bir müddət gözləyə və ya başqa IP-yə keçə bilərsiniz (məsələn, VPN-i açıb/qapatmaqla və ya WiFi-dan mobil dataya keçməklə).
+ Bu məzmun hazırda seçilən məzmun ölkəsi üçün əlçatan deyil. \n\nSeçiminizi \"Tənzimləmələr > Məzmun > İlkin məzmun ölkəsi\"- dən dəyişin.
diff --git a/app/src/main/res/values-b+ast/strings.xml b/app/src/main/res/values-b+ast/strings.xml
index 51b4fdec0..81b212f80 100644
--- a/app/src/main/res/values-b+ast/strings.xml
+++ b/app/src/main/res/values-b+ast/strings.xml
@@ -43,9 +43,6 @@
Tarrezmes
Formatu de videu predetermináu
Prietu
- mil
- mill.
- mil mill.
Precísase esti permisu p\'abrir
\nnel mou ventanu
Retu de reCAPTCHA
diff --git a/app/src/main/res/values-b+uz+Latn/strings.xml b/app/src/main/res/values-b+uz+Latn/strings.xml
index b556da756..2be37ea7c 100644
--- a/app/src/main/res/values-b+uz+Latn/strings.xml
+++ b/app/src/main/res/values-b+uz+Latn/strings.xml
@@ -267,9 +267,6 @@
Obunachilar yo\'q
Hozirda tanlangan xizmatni yoqish:
- B
- M
- k
Qayta
Audio
Video
diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml
index 9f40ae48f..ef7ef98c3 100644
--- a/app/src/main/res/values-be/strings.xml
+++ b/app/src/main/res/values-be/strings.xml
@@ -85,7 +85,7 @@
Прайграванне ў фонавым рэжыме
Прайграванне ва ўсплывальным акне
Кантэнт
- Паказваць кантэнт 18+
+ Кантэнт з ўзроставым абмежаваннем
Ужывую
Спампоўкі
Спампоўкі
@@ -106,8 +106,8 @@
Апавяшчэнне NewPipe
Апавяшчэнні для прайгравальніка NewPipe
[Невядома]
- Перайсці ў фон
- Перайсці ў акно
+ Перайсці ў фонавы рэжым
+ Перайсці ў аконны рэжым
Перайсці ў галоўнае акно
Імпартаваць даныя
Экспартаваць даныя
@@ -159,9 +159,6 @@
Відэа
Аўдыя
Паспрабаваць зноў
- тыс.
- млн
- млрд
Няма падпісчыкаў
- %s падпісчык
@@ -430,7 +427,7 @@
Уключыць гук
Адключыць гук
Дадаць у чаргу
- Даданае ў чаргу
+ Дададзена у чаргу
Чарга прайгравання
Найбольш папулярнае
Лакальнае
@@ -579,7 +576,7 @@
Шукайце серверы, якія вам даспадобы, на %s
Паказваць метаданыя
Ігнараваць падзеі апаратных медыякнопак
- Паказваць змесціва, магчыма непрыдатнае для дзяцей, таму што яно мае ўзроставыя абмежаванні (напрыклад, 18+)
+ Паказваць змесціва, якое можа быць непрыдатным для дзяцей, бо мае ўзроставыя абмежаванні (напрыклад, 18+)
Праверце, ці не існуе заяўкі з абмеркаваннем вашай праблемы. Дублікаты марнуюць наш час і праз гэта адцягваецца вырашэнне сапраўдных задач.
Адбылася памылка, глядзіце апавяшчэнне
Збой плэера
@@ -600,8 +597,8 @@
- %s новых трансляцый
Каментарыі
- У чаргу далей
- У чарзе наступны
+ Дадаць у чаргу наступным
+ Дададзена у чаргу (наступным)
Загрузка звестак аб стрыме…
Ідзе апрацоўка… Крыху пачакайце
Дублікат дададзены %d раз(ы)
@@ -695,23 +692,20 @@
Радыё
Паказваць наступныя патокі
Паказаць/схаваць трансляцыі
- Гэты кантэнт яшчэ не падтрымліваецца NewPipe.
-\n
-\nСпадзяюся, ён будзе падтрымлівацца ў наступных версіях.
+ Гэты кантэнт яшчэ не падтрымліваецца NewPipe.\n\nСпадзяёмся, што падтрымка з\'явіцца ў наступных версіях.
Старонка плэй-ліста
Паказваць мініяцюру
Выкарыстоўваць мініяцюру як фон для экрана блакіроўкі і апавяшчэнняў
Для гэтага дзеяння не знойдзены прыдатны файлавы менеджар. \nУсталюйце файлавы менеджар або паспрабуйце адключыць «%s» у наладах спампоўвання
Гэты кантэнт недаступны ў вашай краіне.
- Гэта трэк SoundCloud Go+, прынамсі ў вашай краіне, таму NewPipe не можа трансляваць ці спампоўваць яго.
- Гэта змесціва з\'яўляецца прыватным, таму NewPipe не можа яго трансляваць або спампоўваць.
- Гэта відэа даступна толькі для падпісчыкаў YouTube Music Premium, таму NewPipe не можа яго трансляваць або спампоўваць.
+ Гэта трэк SoundCloud Go+ (прынамсі ў вашай краіне), таму NewPipe не можа яго прайграць або спампаваць.
+ Гэты кантэнт прыватны, таму NewPipe не можа яго прайграць або спампаваць.
+ Гэта відэа даступна толькі для падпісчыкаў YouTube Music Premium, таму NewPipe не можа яго прайграць або спампаваць.
Уліковы запіс спынены
- %s дае наступную прычыну:
Вартае ўвагі
Унутраная
Прагледжаныя цалкам
- Гэты кантэнт даступны толькі для аплачаных карыстальнікаў, таму NewPipe не можа яго трансляваць або спампоўваць.
+ Гэты кантэнт даступны карыстальнікам толькі за плату, таму NewPipe не можа яго прайграць або спампаваць.
Даступна для некаторых сэрвісаў, звычайна значна хутчэй, але можа перадаваць абмежаваную колькасць элементаў і не ўсю інфармацыю (можа адсутнічаць працягласць, тып элемента, паказчык трансляцыі)
Узроставае абмежаванне
Для гэтага дзеяння не знойдзены прыдатны файлавы менеджар. \nУсталюйце файлавы менеджар, сумяшчальны з Storage Access Framework
@@ -733,7 +727,7 @@
Аддаваць перавагу арыгінальнаму гуку
Аддаваць перавагу апісальнаму гуку
Выбіраць гукавую дарожку з апісаннем для людзей са слабым зрокам, калі яна ёсць
- Аўдыя: %s
+ Аўдыядарожка: %s
Гукавая дарожка
Выберыце гукавую дарожку для знешніх прайгравальнікаў
Невядомая
@@ -823,4 +817,19 @@
Пошук %1$s
Пошук %1$s (%2$s)
Спадабалася
+ «Дазволіць паказ па-над астатнімі праграмамі»
+ %s тыс.
+ %s млн
+ %s млрд
+ Выдаліць файл
+ Выдаліць запіс
+ Старонка SoundCloud Top 50 выдалена
+ Трэнды – музыка
+ Запіс выдалены
+ Трэнды – гульні
+ Трэнды – падкасты
+ Трэнды – фільмы і перадачы
+ Гэты кантэнт недаступны для цяперашняй краіны кантэнту.\n\nЯе можна змяніць праз «Налады > Кантэнт > Прадвызначаная краіна кантэнту».
+ 21 ліпеня 2025 года YouTube спыніў падтрымку аб\'яднанай старонкі трэндаў. NewPipe замяніў старонку трэндаў на трэнды трансляцый.\n\nТаксама можна выбраць іншыя старонкі трэндаў праз «Налады > Кантэнт > Змесціва галоўнай старонкі».
+ Аб\'яднаныя трэнды YouTube выдалены
diff --git a/app/src/main/res/values-ber/strings.xml b/app/src/main/res/values-ber/strings.xml
index 3912381fc..39247f49b 100644
--- a/app/src/main/res/values-ber/strings.xml
+++ b/app/src/main/res/values-ber/strings.xml
@@ -45,9 +45,6 @@
∞ ⵉⴼⵉⴷⵢⵓⵜⵏ
100+ ⵉⴼⵉⴷⵢⵓⵜⵏ
- ⴱ
- ⵎ
- ⴽ
ⴰⵎⵙⵍⴰⵢ
ⴰⴼⵉⴷⵢⵓ
ⵉⵔⵉⵜⵏ
diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml
index 0d83f6c0c..69f8a8e9b 100644
--- a/app/src/main/res/values-bg/strings.xml
+++ b/app/src/main/res/values-bg/strings.xml
@@ -163,8 +163,8 @@
Само веднъж
Файл
Мини във фонов режим
- Мини към нов прозорец
- Мини в основен режим
+ Мини в нов прозорец
+ Мини към основен режим
Внасяне на база данни
Изнасяне на база данни
Замества текущата ви история, абонаменти, списъци за възпроизвеждане и (по избор) настройки
@@ -183,9 +183,6 @@
Името на файла не може да бъде празно
Възникна грешка: %1$s
Не са налични източници за изтегляне
- хил.
- млн.
- млрд.
Няма абонати
Създай
Откажи
@@ -261,7 +258,7 @@
Нов Плейлист
Преименувай
Име
- Добави Към Плейлист
+ Добави към плейлист
Задай като миниатюра на плейлиста
Миниатюрата на плейлиста е сменена
Премахни отметката
@@ -280,7 +277,7 @@
Докладвай за извънредни грешки
Внасяне
Внасяне от
- Изнеси в
+ Изнасяне във
Внасяне…
Изнасяне…
Файл с данни за внасяне
@@ -419,7 +416,6 @@
Страница на плейлиста
Глави
Лиценз
- %s посочва следната причина:
Маркери
Поверителност
Език
@@ -664,7 +660,7 @@
Въведете URL адреса на инстанцията
Аудио: %s
Покажи информация за канала
- Автоматично генерирани (не е намерен ъплоудер)
+ Авто-генерирани (не е намерен ъплоудер)
Създай известие за грешка
NewPipe може автоматично да проверява за нови версии от време на време и да ви известява при наличие.
\nИскате ли да го включите?
@@ -819,4 +815,24 @@
Харесвания
Страница SoundCloud Top 50 е премахната
SoundCloud преустанови оригиналните класации Топ 50. Съответният раздел е премахнат от главната ви страница.
+ YouTube преустанови комбинираната страница с популярни от 21 юли 2025 г. NewPipe замени стандартната страница с популярни с популярни предавания на живо.\n\nМожете също да изберете различни популярни страници в „Настройки > Съдържание > Съдържание на главната страница“.
+ YouTube комбинирани популярни са премахнати
+ Популярни игри
+ Популярни подкасти
+ Популярни филми и сериали
+ Популярна музика
+ %s хил.
+ %s млн.
+ %s млрд.
+ За да използвате изскачащия плейър, моля, изберете %1$s в следното меню с настройки на Android и активирайте %2$s.
+ “Разреши показване върху други приложения”
+ Изтриване на файл
+ Изтриване на запис
+ Записът е изтрит
+ Профилът е прекратен\n\n%1$s предоставя тази причина: %2$s
+ HTTP грешка 403, получена от сървъра по време на възпроизвеждане, вероятно причинена от изтичане на URL адреса за стрийминг или забрана на IP адреса
+ HTTP грешка %1$s получена от сървъра по време на възпроизвеждане
+ HTTP грешка 403, получена от сървъра по време на възпроизвеждане, вероятно причинена от забрана на IP адреса или проблеми с деобфускацията на URL адреси за стрийминг
+ %1$s отказа да предостави данни, като поиска вход, за да потвърди, че заявителят не е бот.\n\nВашият IP адрес може да е временно забранен от %1$s. Можете да изчакате известно време или да превключите към друг IP адрес (например като включите/изключите VPN или като превключите от WiFi към мобилни данни).
+ Това съдържание не е налично за текущо избраната държава на съдържанието.\n\nПроменете избора си от \"Настройки > Съдържание > Държава на съдържанието по подразбиране\".
diff --git a/app/src/main/res/values-bn-rBD/strings.xml b/app/src/main/res/values-bn-rBD/strings.xml
index ddc32e418..2b0ffe918 100644
--- a/app/src/main/res/values-bn-rBD/strings.xml
+++ b/app/src/main/res/values-bn-rBD/strings.xml
@@ -82,9 +82,6 @@
ভিডিও
অডিও
পুনরায় চেষ্টা করো
- হা
- M
- বি
শুরু
বিরতি
diff --git a/app/src/main/res/values-bn-rIN/strings.xml b/app/src/main/res/values-bn-rIN/strings.xml
index e6269b5b9..a79319ee3 100644
--- a/app/src/main/res/values-bn-rIN/strings.xml
+++ b/app/src/main/res/values-bn-rIN/strings.xml
@@ -307,4 +307,8 @@
বিজ্ঞপ্তিতে প্রদর্শিত ভিডিও থাম্বনেল 16:9 থেকে 1:1 অনুপাতের করুন (বিকৃতি দেখা যেতে পারে)
অদলবদল
কিছু না
+ হ্যাঁ
+ না
+ সার্চ
+ খুঁজুন
diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml
index 715c9146e..8d767a173 100644
--- a/app/src/main/res/values-bn/strings.xml
+++ b/app/src/main/res/values-bn/strings.xml
@@ -104,9 +104,6 @@
কোন ভিডিও নেই
কোন ভিউ নেই
কোন সাবস্ক্রাইবার নেই
- B
- M
- K
পুনরায় চেষ্টা করো
অডিও
ভিডিও
@@ -299,7 +296,7 @@
এক প্লেয়ার থেকে অন্য প্লেয়ারে পরিবর্তন করলে তোমার সারি প্রতিস্থাপিত হতে পারে
কিউ মোছার আগে নিশ্চিত করো
কমপ্যাক্ট বিজ্ঞপ্তিতে প্রদর্শন করতে তুমি সর্বাধিক তিনটি ক্রিয়া নির্বাচন করতে পারো!
- নিচের প্রতিটি প্রজ্ঞাপন ক্রিয়া সম্পাদনা করো। ডান দিকের চেকবাক্স ব্যবহার করে কম্প্যাক্ট নোটিফিকেশনে দেখানোর জন্য তিনটি পর্যন্ত নির্বাচন করো
+ নিচের প্রতিটি প্রজ্ঞাপন ক্রিয়া সম্পাদনা করুন । ডান দিকের চেকবাক্স ব্যবহার করে কম্প্যাক্ট নোটিফিকেশনে দেখানোর জন্য তিনটি পর্যন্ত নির্বাচন করুন ।
প্রদর্শিত ভিডিও থাম্বনেইল ১৬:৯ থেকে ১:১অনুপাতে পরিবর্তন করো
ফিড
ওভাররাইট
@@ -543,7 +540,6 @@
\'%s\' এর জন্য ফিড প্রক্রিয়া করা যাচ্ছে না।
বর্ণনার লেখা নির্বাচন করা নিষ্ক্রিয় করো
বর্ণনার লেখা নির্বাচন করা সক্ষম করো
- %s এই কারণ বলছে:
প্রক্রিয়াকরণ ফিডে ত্রুটি
ওয়েবসাইট খুলুন
অ্যাকাউন্ট ধ্বংসকৃত
@@ -632,4 +628,8 @@
ভুক্তি মুছতে ডানে-বামে সরাও
সম্প্রচার বিষয়ক তথ্য প্রক্রিয়ারত…
প্লেব্যাক লোড বিরতির আকার
+ হ্যা
+ না
+ প্লেলিস্ট
+ উদাহরণস্বরূপ, যদি আপনি ভাঙা ফিজিক্যাল বোতাম সহ একটি হেডসেট ব্যবহার করেন তবে এটি কার্যকর
diff --git a/app/src/main/res/values-br/strings.xml b/app/src/main/res/values-br/strings.xml
index a0a7744f6..dfff3c2cc 100644
--- a/app/src/main/res/values-br/strings.xml
+++ b/app/src/main/res/values-br/strings.xml
@@ -117,5 +117,4 @@
Lenn ar video, pad:
Titouroù:
Video
-
diff --git a/app/src/main/res/values-bs/strings.xml b/app/src/main/res/values-bs/strings.xml
index 4921a6aa8..ff0b7003a 100644
--- a/app/src/main/res/values-bs/strings.xml
+++ b/app/src/main/res/values-bs/strings.xml
@@ -28,7 +28,7 @@
Otkazana pratnja kanala
Nije moguće promijeniti pratnju
Nije moguće ažurirati pratnju
- Instalirajte nedostajeću Kode aplikaciju\?
+ Instalirati nedostajuću Kore aplikaciju?
Obilježeni Popisi
Iskačni prozor
Izaberite Podprozor
@@ -43,9 +43,9 @@
Zadani režim za iskačući prozor
Prekinite pokretač
Prikažite postavku da biste video preko KODI medijskog centra video pokrenuli
- Skalirajte sličicu na 1:1 omjer
+ Izrežite sličicu na omjer slike 1:1
Prvo radno dugme
- Skalirajte video sličicu prikazanu u obavijesti sa 16:9 na 1:1 omjer (može uvesti poremećaje)
+ Izrežite sličicu videa prikazanu u obavještenju sa omjera stranica 16:9 na 1:1
Drugo radno dugme
Treće radno dugme
Četvrto radno dugme
@@ -53,7 +53,7 @@
Možete najviše tri radnje odabrati za prikaz u kompaktnom obavještaju!
Ponovi
Pomiješajte
- Uredite svaku radnju obavještenja ispod pri dodiru na nju. Odaberite bar tri od njih za prikaz u kompaktnom obavještenju koristeći potvrdne okvire s desne strane
+ Uredite svaku radnju obavještenja ispod dodirom na nju. Odaberite do tri od njih koje će biti prikazane u kompaktnom obavještenju pomoću potvrdnih okvira s desne strane.
Ništa
Obojite obavještenje
Učitavanje
@@ -62,7 +62,7 @@
Zvuk
Zadani video format
Tema
- Noćna Tema
+ Noćna tema
Svijetla
Tamna
Zapamtite podešavanja za iskočne prozore
@@ -114,4 +114,709 @@
Pokrenite s KODI-jem
Vrijeme premotavanja naprijed/nazad
Aktivni pokretni red će biti zamijenjen
-
\ No newline at end of file
+ Da
+ Ne
+ Pretraži %1$s
+ Pretraži %1$s (%2$s)
+ Plejliste
+ Uredite svaku radnju obavještenja ispod dodirom na nju. Prve tri radnje (reprodukcija/pauza, prethodno i sljedeće) postavlja sistem i ne mogu se prilagođavati.
+ Veličina intervala učitavanja reprodukcije
+ Promijenite veličinu intervala učitavanja progresivnog sadržaja (trenutno %s). Niža vrijednost može ubrzati njihovo početno učitavanje
+ Zanemari događaje hardverskih medijskih tipki
+ Korisno, na primjer, ako koristite slušalice s pokvarenim fizičkim tipkama
+ Preferiraj originalni audio
+ Odaberite originalni audio zapis bez obzira na jezik
+ Preferiraj opisni audio
+ Odaberite audio zapis s opisima za osobe s oštećenim vidom ako su dostupni
+ Odaberite gestu za lijevu polovinu ekrana igrača
+ Radnja lijevog pokreta
+ Odaberite gestu za desnu polovinu ekrana igrača
+ Radnja desnog gesta
+ Svjetlina
+ Volumen
+ Nema
+ Prikaži savjet \"Drži za dodavanje u red\"
+ Prikaži savjet prilikom pritiska na pozadinu ili iskačuće dugme u videu \"Detalji:\"
+ Nepodržani URL
+ URL nije prepoznat. Otvoriti s drugom aplikacijom?
+ Zadana zemlja sadržaja
+ Zadani jezik sadržaja
+ PeerTube instance
+ Odaberite svoje omiljene PeerTube instance
+ Pronađite instance koje vam se sviđaju na %s
+ Dodaj instancu
+ Unesite URL instance
+ Nije moguće validirati instancu
+ Podržani su samo HTTPS URL-ovi
+ Instanca već postoji
+ Pokretač
+ Ponašanje
+ Video i audio
+ Historija i keš memorija
+ Izgled
+ Debug
+ Nadogradnje
+ Obavještenje za igrača
+ Konfigurišite obavještenja o trenutno reprodukovanom toku
+ Sigurnosna kopija i vraćanje
+ Reprodukcija u pozadini
+ Reprodukcija u skočnom modu
+ Sadržaj
+ Prikaži sadržaj s ograničenjem za uzrast
+ Prikaži sadržaj koji je možda neprikladan za djecu jer ima starosno ograničenje (npr. 18+)
+ Uključite \"Ograničeni način rada\" na YouTubeu
+ YouTube nudi \"Ograničeni način rada\" koji skriva potencijalno sadržaj za odrasle
+ Ovaj video ima dobno ograničenje.\n\nUključite \"%1$s\" u postavkama ako ga želite pogledati.
+ Ovaj video ima dobno ograničenje. \nZbog novih YouTube pravila o videozapisima s dobnim ograničenjem, NewPipe ne može pristupiti nijednom od svojih video tokova i stoga ga ne može reproducirati.
+ Uživo
+ Preuzimanja
+ Preuzimanja
+ Učitavanje metapodataka…
+ Izvještaj o grešci
+ Sve
+ Kanali
+ Plejliste
+ Videozapisi
+ Snimke
+ Korisnici
+ Događanja
+ Pjesme
+ Albuma
+ Umjetnici
+ Onemogućeno
+ Rasčisti
+ Najbolja rezolucija
+ Poništi
+ Datoteka je izbrisana
+ Reproduciraj sve
+ Uvijek
+ Samo jednom
+ Datoteka
+ Obavijesti
+ Obavještenje o novoj cijevi
+ Obavještenja za NewPipeovog igrača
+ Obavještenje o ažuriranju aplikacije
+ Obavještenja za nove verzije NewPipe-a
+ Obavještenje o hešu videa
+ Obavještenja o napretku heširanja videa
+ Novi tokovi
+ Obavještenja o novim tokovima za pretplatnike
+ Obavještenje o grešci
+ Obavještenja za prijavu grešaka
+ [Nepoznato]
+ Prebaci na pozadinu
+ Prebaci na skočni prozor
+ Prebaci na glavni
+ Uvoz baze podataka
+ Izvoz baze podataka
+ Obriši reCAPTCHA kolačiće
+ reCAPTCHA kolačići su obrisani
+ Zaobilazi vašu trenutnu historiju, pretplate, liste pjesama i (opcionalno) postavke
+ Izvoz historije, pretplata, plejlista i postavki
+ Obrišite kolačiće koje NewPipe pohranjuje kada riješite reCAPTCHA
+ Obriši historiju gledanja
+ Briše historiju reprodukovanih tokova i pozicije reprodukcije
+ Izbrisati cijelu historiju gledanja?
+ Historija gledanja je izbrisana
+ Brisanje pozicija reprodukcije
+ Briše sve pozicije reprodukcije
+ Izbrisati sve pozicije reprodukcije?
+ Pozicije reprodukcije su izbrisane
+ Obriši historiju pretraživanja
+ Briše historiju ključnih riječi pretrage
+ Izbrisati cijelu historiju pretraživanja?
+ Historija pretrage je izbrisana
+ Brzi način rada
+ Pomakni glavni birač kartica na dno
+ Položaj glavnih kartica
+ Greška
+ Vanjska pohrana nije dostupna
+ Preuzimanje na eksternu SD karticu nije moguće. Poništiti lokaciju mape za preuzimanje?
+ Greška mreže
+ Nije moguće učitati sve sličice
+ Nije moguće analizirati web stranicu
+ Sadržaj nije dostupan
+ Nije moguće postaviti meni za preuzimanje
+ Aplikacija/korisnički interfejs se srušio/la
+ Nije moguće reproducirati ovaj tok
+ Došlo je do nepopravljive greške igrača
+ Oporavak od greške igrača
+ Vanjski playeri ne podržavaju ove vrste linkova
+ Nisu pronađeni video tokovi
+ Nisu pronađeni audio tokovi
+ Datoteka je premještena ili izbrisana
+ Fascikla sa popisima
+ Nema takve datoteke/izvora sadržaja
+ Datoteka ne postoji ili nedostaje dozvola za čitanje ili pisanje u nju
+ Naziv datoteke ne može biti prazan
+ Došlo je do greške: %1$s
+ Nema dostupnih tokova za preuzimanje
+ Nije moguće pročitati sačuvane kartice, pa se koriste zadane
+ Vrati zadane postavke
+ Želite li vratiti zadane postavke?
+ Dozvoli prikaz preko drugih aplikacija
+ Da biste koristili Popup Player, odaberite %1$s u sljedećem meniju postavki Androida i omogućite %2$s.
+ \"Dozvoli prikaz preko drugih aplikacija\"
+ NewPipe je naišao na grešku, dodirnite za prijavu
+ Došlo je do greške, pogledajte obavještenje
+ Žao mi je, to se nije trebalo desiti.
+ Prijavi putem e-pošte
+ Kopiraj formatirani izvještaj
+ Izvještaj na GitHubu
+ Molimo Vas da provjerite da li već postoji problem koji se odnosi na Vaš pad sistema. Prilikom kreiranja duplikata tiketa, oduzimate nam vrijeme koje bismo mogli posvetiti ispravljanju samog problema.
+ Izvinite, ali nešto je pošlo po zlu.
+ Prijavi
+ Info:
+ Šta se dogodilo:
+ Šta:\\nZahtjev:\\nJezik sadržaja:\\nZemlja sadržaja:\\nJezik aplikacije:\\nUsluga:\\nVremenska oznaka:\\nPaket:\\nVerzija:\\nVerzija OS-a:
+ Vaš komentar (na engleskom):
+ Detalji:
+ Reproduciraj video, trajanje:
+ Sličica avatara osobe koja je postavila sliku
+ Sviđanja
+ Nesviđa mi se
+ Komentari
+ Povezane stavke
+ Opis
+ Bez rezultata
+ Ovdje nema ničega osim cvrčaka
+ Uvoz ili izvoz pretplata iz menija s tri tačke
+ Prevucite da promijenite redoslijed
+ Video
+ Audio
+ Pokušaj ponovo
+ %sK
+ %sM
+ %sB
+ Uključi/isključi uslugu, trenutno odabrana:
+ Nema pretplatnika
+ Broj pretplatnika nije dostupan
+ Nema pregleda
+ Niko ne gleda
+ Niko ne sluša
+ Nema videozapisa
+ 100+ videa
+ ∞ videozapisi
+ Nema komentara
+ Komentari su onemogućeni
+ Nema tokova
+ Nema prijenosa uživo
+ Početak
+ Pauziraj
+ Napravi
+ Izbriši
+ Izbriši datoteku
+ Izbriši unos
+ Kontrolni zbir
+ Raspusti
+ Preimenuj
+ Naziv datoteke
+ Teme
+ Greška
+ Preuzimanje NewPipe-a
+ Dodirnite za detalje
+ Izračunavanje heša
+ Molimo pričekajte…
+ Kopirano u međuspremnik
+ Kopiranje u međuspremnik nije uspjelo
+ Molimo vas da kasnije u postavkama definišete folder za preuzimanje
+ Još nije postavljen folder za preuzimanje, odaberite zadani folder za preuzimanje sada
+ Ova dozvola je potrebna za \notvaranje u skočnom prozoru
+ 1 stavka je izbrisana.
+ reCAPTCHA izazov
+ Pritisnite \"Gotovo\" kada riješite problem
+ Zatražen je reCAPTCHA izazov
+ Riješi
+ Gotovo
+ Preuzimanje
+ Dozvoljeni znakovi u nazivima datoteka
+ Nevažeći znakovi se zamjenjuju ovom vrijednošću
+ Zamjenski lik
+ Slova i brojevi
+ Većina specijalnih znakova
+ O NewPipe-u
+ Licence trećih strana
+ © %1$s od %2$s pod %3$s
+ Dozvole
+ Besplatno lagano tokanje na Androidu.
+ Doprinesite
+ Bez obzira da li imate ideje za: prevod, promjene dizajna, čišćenje koda ili zaista velike promjene koda - pomoć je uvijek dobrodošla. Što se više uradi, to bolje postaje!
+ Pogledajte na GitHubu
+ Donirajte
+ NewPipe je razvijen od strane volontera koji svoje slobodno vrijeme provode pružajući vam najbolje korisničko iskustvo. Doprinesite programerima kako biste ih učinili još boljim dok uživaju u šoljici kafe.
+ Vratite
+ Web stranica
+ Posjetite web stranicu NewPipe za više informacija i novosti.
+ Politika privatnosti kompanije NewPipe
+ Projekat NewPipe veoma ozbiljno shvata vašu privatnost. Stoga aplikacija ne prikuplja nikakve podatke bez vašeg pristanka.\nPolitika privatnosti NewPipe-a detaljno objašnjava koji se podaci šalju i pohranjuju kada pošaljete izvještaj o padu sistema.
+ Pročitajte politiku privatnosti
+ NewPipe-ova licenca
+ NewPipe je copyleft libre softver: Možete ga koristiti, proučavati, dijeliti i poboljšavati po volji. Konkretno, možete ga redistribuirati i/ili mijenjati pod uvjetima GNU Opće javne licence koju je objavila Fondacija za slobodni softver, bilo verzije 3 Licence ili (po vašem izboru) bilo koje kasnije verzije.
+ Pročitaj licencu
+ Često postavljana pitanja
+ Ako imate problema s korištenjem aplikacije, obavezno pogledajte ove odgovore na česta pitanja!
+ Pogledajte na web stranici
+ Historija
+ Historija
+ Želite li izbrisati ovu stavku iz historije pretrage?
+ Posljednje igrano
+ Najigranije
+ Sadržaj glavne stranice
+ Koje kartice se prikazuju na glavnoj stranici
+ Prevucite stavke da biste ih uklonili
+ Prazna stranica
+ Stranica kioska
+ Zadani kiosk
+ Stranica kanala
+ Odaberite kanal
+ Još nema pretplata na kanale
+ Odaberite listu za reprodukciju
+ Još nema oznaka za plejlistu
+ Odaberite kiosk
+ Izvezeno
+ Uvezeno
+ Nema važeće ZIP datoteke
+ Upozorenje: Nije moguće uvesti sve datoteke.
+ Ovo će poništiti vašu trenutnu postavku.
+ Želite li uvesti i postavke?
+ Nije moguće učitati komentare
+ Odaberite grupu feedova
+ Još nije kreirana nijedna grupa feedova
+ U trendu
+ Top 50
+ Novo i popularno
+ Lokalno
+ Nedavno dodano
+ Najpopularnije
+ Konferencije
+ Red za reprodukciju
+ Ukloni
+ Detalji
+ Postavke zvuka
+ Audio: %s
+ Zvučni zapis
+ Držite za dodavanje u red
+ Prikaži detalje kanala
+ Stavi u red
+ Stavljeno u red čekanja
+ Stavi sljedeće u red
+ Sljedeće u redu čekanja
+ Počni reprodukciju u pozadini
+ Počnite igrati u iskačućem prozoru
+ Učitavanje detalja toka…
+ Otvori ladicu
+ Zatvori ladicu
+ Preferirana akcija \'otvaranja\'
+ Zadana radnja pri otvaranju sadržaja — %s
+ Video plejer
+ Pozadinski plejer
+ Iskačući plejer
+ Uvijek pitajte
+ Dobijanje informacija…
+ Učitavanje traženog sadržaja
+ Nova plejlista
+ Liste za reprodukciju koje su sive već sadrže ovu stavku.
+ Preimenuj
+ Ime
+ Dodaj na listu pjesama
+ Obrada… Može potrajati trenutak
+ Isključi zvuk
+ Uključi zvuk
+ Postavi kao sličicu za reprodukciju
+ Poništi trajnu sličicu
+ Označi plejlistu
+ Ukloni oznaku
+ Izbrisati ovaj popis?
+ Plejlista je kreirana
+ Plejlista
+ Duplikat dodan %d puta
+ Sličica plejliste je promijenjena.
+ Automatski generirano (nije pronađen korisnik koji je otpremio)
+ Nema titlova
+ Prilagođeno
+ Popuni
+ Uvećanje
+ Automatski generirano
+ Titlovi
+ Izmijenite veličinu teksta titlova i stilove pozadine za player. Za primjenu je potrebno ponovno pokretanje aplikacije
+ LeakCanary nije dostupan
+ Praćenje curenja memorije može uzrokovati da aplikacija prestane reagirati prilikom ispisa heap memorije
+ Prikaži curenje memorije
+ Prijavi greške izvan životnog ciklusa
+ Prisilno prijavljivanje izuzetaka neisporučenih Rx zahtjeva izvan životnog ciklusa fragmenta ili aktivnosti nakon odlaganja
+ Prikaži originalno vrijeme prije stavki
+ Originalni tekstovi iz usluga bit će vidljivi u stavkama toka
+ Onemogući tuneliranje medija
+ Onemogućite tuneliranje medija ako se pojavi crni ekran ili se prilikom reprodukcije videa pojavi prekid.
+ Tuneliranje medija je onemogućeno prema zadanim postavkama na vašem uređaju jer je poznato da vaš model uređaja to ne podržava.
+ Prikaži indikatore slike
+ Prikažite Picasso obojene trake preko slika koje označavaju njihov izvor: crvena za mrežu, plava za disk i zelena za memoriju
+ Prikaži \"Sruši plejer\"
+ Prikazuje opciju pada sistema prilikom korištenja plejera
+ Pokreni provjeru za nove tokove
+ Sruši aplikaciju
+ Prikaži traku s upozorenjem o grešci
+ Kreiraj obavještenje o grešci
+ Uvoz
+ Uvoz iz
+ Izvoz u
+ Uvoz…
+ Izvoz…
+ Uvoz datoteke
+ Prethodni izvoz
+ Nije moguće uvesti pretplate
+ Nije moguće izvesti pretplate
+ Uvoz YouTube pretplata iz Google arhive:\n\n1. Idite na ovaj URL: %1$s\n2. Prijavite se kada se to od vas zatraži\n3. Kliknite na \"Svi podaci uključeni\", zatim na \"Poništi odabir svih\", a zatim odaberite samo \"pretplate\" i kliknite na \"U redu\"\n4. Kliknite na \"Sljedeći korak\", a zatim na \"Kreiraj izvoz\"\n5. Kliknite na dugme \"Preuzmi\" nakon što se pojavi\n6. Kliknite na UVOZ DATOTEKE ispod i odaberite preuzetu .zip datoteku\n7. [Ako uvoz .zip datoteke ne uspije] Izvucite .csv datoteku (obično pod \"YouTube i YouTube Music/pretplate/pretplate.csv\"), kliknite na UVOZ DATOTEKE ispod i odaberite izvučenu csv datoteku
+ Uvezite SoundCloud profil unosom URL-a ili vašeg ID-a:\n\n1. Omogućite \"desktop mode\" u web pregledniku (stranica nije dostupna za mobilne uređaje)\n2. Idite na ovaj URL: %1$s\n3. Prijavite se kada se to od vas zatraži\n4. Kopirajte URL profila na koji ste preusmjereni.
+ tvoj ID, soundcloud.com/tvojID
+ Imajte na umu da ova operacija može biti skupa za mrežu.\n\nŽelite li nastaviti?
+ Kontrole brzine reprodukcije
+ Brzina
+ Točka glasa
+ Otkačite (može uzrokovati distorziju)
+ Premotavanje unaprijed tokom tišine
+ Korak
+ Resetuj
+ Postotak
+ Poluton
+ Kako bismo se pridržavali Opće uredbe o zaštiti podataka (GDPR), ovim putem skrećemo vašu pažnju na politiku privatnosti kompanije NewPipe. Molimo vas da je pažljivo pročitate.\nMorate je prihvatiti da biste nam poslali izvještaj o grešci.
+ Prihvati
+ Odbij
+ Bez ograničenja
+ Ograničenje rezolucije prilikom korištenja mobilnih podataka
+ Obavještenja o novim tokovima
+ Obavijesti me o novim tokovima s pretplata
+ Učestalost provjere
+ Potrebna mrežna veza
+ Bilo koja mreža
+ Nadogradnje
+ Prikaži obavještenje za podsticanje ažuriranja aplikacije kada je dostupna nova verzija
+ Provjeri ažuriranja
+ NewPipe može automatski provjeravati nove verzije s vremena na vrijeme i obavijestiti vas kada budu dostupne.\nŽelite li ovo omogućiti?
+ Ručno provjerite nove verzije
+ Minimiziraj pri prebacivanju aplikacija
+ Radnja prilikom prelaska na drugu aplikaciju iz glavnog video plejera — %s
+ Nema
+ Minimiziraj na pozadinski plejer
+ Minimiziraj da bi se player pojavio u skočnom prozoru
+ Automatski pokreni reprodukciju — %s
+ Samo na Wi-Fi mreži
+ Nikad
+ Način prikaza liste
+ Spisak
+ Rešetka
+ Kartica
+ Automatski
+ Pregled sličice trake za pretraživanje
+ Visok kvalitet (veći)
+ Nizak kvalitet (manji)
+ Ne prikazuj
+ Koristite najnoviju verziju NewPipe-a
+ Ažuriranje NewPipe-a je dostupno!
+ Dodirnite za preuzimanje %s
+ Završeno
+ Na čekanju
+ pauzirano
+ u redu čekanja
+ naknadna obrada
+ oporavlja se
+ Stavi u red
+ Sistem je odbio akciju
+ Provjera ažuriranja…
+ Preuzimanje nije uspjelo
+ Resetiraj postavke
+ Resetujte sve postavke na njihove zadane vrijednosti
+ Resetovanjem svih postavki poništit ćete sve svoje željene postavke i ponovo pokrenuti aplikaciju.\n\nJeste li sigurni da želite nastaviti?
+ Generiraj jedinstveno ime
+ Prebriši
+ Datoteka s ovim imenom već postoji
+ Preuzeta datoteka s ovim nazivom već postoji
+ ne može prepisati datoteku
+ U toku je preuzimanje s ovim imenom
+ Postoji preuzimanje s ovim nazivom na čekanju
+ Prikaži grešku
+ Datoteka ne može biti kreirana
+ Nije moguće kreirati odredišnu mapu
+ Nije moguće uspostaviti sigurnu vezu
+ Nije moguće pronaći server
+ Ne mogu se povezati sa serverom
+ Server ne šalje podatke
+ Server ne prihvata višenitna preuzimanja, pokušajte ponovo sa @string/msg_threads = 1
+ Nije pronađeno
+ Naknadna obrada nije uspjela
+ NewPipe je zatvoren tokom rada na datoteci
+ Nema dovoljno slobodnog prostora na uređaju
+ Nema više prostora na uređaju
+ Napredak je izgubljen jer je datoteka izbrisana
+ Vremensko ograničenje veze
+ Nije moguće oporaviti ovo preuzimanje
+ Obriši historiju preuzimanja
+ Želite li obrisati historiju preuzimanja ili izbrisati sve preuzete datoteke?
+ Izbriši preuzete datoteke
+ Izbrisati sve preuzete datoteke s diska?
+ Zaustavi
+ Maksimalan broj ponovnih pokušaja
+ Maksimalan broj pokušaja prije otkazivanja preuzimanja
+ Prekid na mrežama s ograničenim pristupom
+ Korisno prilikom prelaska na mobilne podatke, iako se neka preuzimanja ne mogu obustaviti
+ Zatvori
+ Ograniči red čekanja za preuzimanje
+ Jedno preuzimanje će se pokrenuti istovremeno
+ Započni preuzimanja
+ Pauziraj preuzimanja
+ Pitaj gdje preuzeti
+ Bit ćete upitani gdje želite sačuvati svako preuzimanje.\nOmogućite birač sistemskih foldera (SAF) ako želite preuzeti na eksternu SD karticu
+ Bit ćete upitani gdje sačuvati svako preuzimanje
+ Koristi birač sistemskih foldera (SAF)
+ \'Okvir za pristup pohrani\' omogućava preuzimanje na eksternu SD karticu
+ Počevši od Androida 10, podržan je samo \'Storage Access Framework\'
+ Odaberite instancu
+ Jezik aplikacije
+ Zadano sistemsko
+ Ukloni gledano
+ Ukloniti gledane videozapise?
+ Ukloni duplikate
+ Ukloniti duplikate?
+ Želite li ukloniti sve duplikatne tokove na ovoj listi za reprodukciju?
+ Videozapisi koji su pregledani prije i poslije dodavanja na listu za reprodukciju bit će uklonjeni.\nJeste li sigurni? Ovo se ne može poništiti!
+ Da, i djelimično odgledani videozapisi
+ Zbog ograničenja ExoPlayera, trajanje pretraživanja je postavljeno na %d sekundi
+ Šta je novo
+ Stranica grupe kanala
+ Grupe kanala
+ Sažetak zadnji put ažuriran: %s
+ Nije učitano: %d
+ Učitavanje feeda…
+ Obrada feeda…
+ Nove stavke feeda
+ Odaberite pretplate
+ Nije odabrana pretplata
+ Prazan naziv grupe
+ Želite li izbrisati ovu grupu?
+ Novo
+ Prikaži samo negrupirane pretplate
+ Sažetak
+ Prag ažuriranja feeda
+ Vrijeme nakon posljednjeg ažuriranja prije nego što se pretplata smatra zastarjelom — %s
+ Uvijek ažuriraj
+ Greška pri učitavanju feeda
+ Nije moguće učitati feed za \'%s\'.
+ Autorov račun je ukinut. \nNewPipe ubuduće neće moći učitavati ovaj sažetak. \nŽeliš li ukinuti pretplatu za ovaj kanal?
+ Režim brzog hranjenja ne pruža više informacija o ovome.
+ Preuzmi iz namjenskog feeda kada je dostupan
+ Dostupno u nekim servisima, obično je mnogo brže, ali može vratiti ograničen broj artikala i često nepotpune informacije (npr. bez trajanja, vrste artikla, bez aktivnog statusa)
+ Omogući brzi način rada
+ Onemogući brzi način rada
+ Mislite li da je učitavanje feeda previše sporo? Ako je tako, pokušajte omogućiti brzo učitavanje (možete ga promijeniti u postavkama ili pritiskom na dugme ispod).\n\nNewPipe nudi dvije strategije učitavanja feeda:\n• Preuzimanje cijelog pretplatničkog kanala, što je sporo, ali potpuno.\n• Korištenje namjenske krajnje tačke usluge, što je brzo, ali obično nije potpuno.\n\nRazlika između ove dvije je u tome što brza obično nema neke informacije, poput trajanja ili vrste stavke (ne može razlikovati videozapise uživo od normalnih) i može vratiti manje stavki.\n\nYouTube je primjer usluge koja nudi ovu brzu metodu sa svojim RSS feedom.\n\nDakle, izbor se svodi na to šta preferirate: brzinu ili precizne informacije.
+ Prikaži sljedeće tokove
+ Prikaži/Sakrij tokove
+ Dohvati kartice kanala
+ Kartice koje treba preuzeti prilikom ažuriranja feeda. Ova opcija nema efekta ako se kanal ažurira pomoću brzog načina rada.
+ Ovaj sadržaj još uvijek nije podržan od strane NewPipe-a.\n\nNadamo se da će biti podržan u budućoj verziji.
+ Sličica avatara kanala
+ Kreirao/la %s
+ Napisao %s
+ Stranica s popisom za reprodukciju
+ Prikaži sličicu
+ Koristite sličicu i za pozadinu zaključanog ekrana i za obavještenja
+ Nedavno
+ Poglavlja
+ Nijedna aplikacija na vašem uređaju ne može ovo otvoriti
+ Nije pronađen odgovarajući upravitelj datoteka za ovu radnju.\nMolimo instalirajte upravitelj datoteka ili pokušajte onemogućiti \'%s\' u postavkama preuzimanja
+ Nije pronađen odgovarajući upravitelj datoteka za ovu radnju.\nMolimo instalirajte upravitelj datoteka kompatibilan sa Storage Access Frameworkom
+ Ovaj sadržaj nije dostupan u vašoj zemlji.
+ Ovo je pjesma na SoundCloud Go+ platformi, barem u vašoj zemlji, tako da je NewPipe ne može strimovati ili preuzeti.
+ Ovaj sadržaj je privatan, tako da ga NewPipe ne može strimovati ili preuzimati.
+ Ovaj video je dostupan samo članovima YouTube Music Premium-a, tako da ga NewPipe ne može strimovati ili preuzeti.
+ Račun ukinut
+ Račun ukinut\n\n%1$s navodi ovaj razlog: %2$s
+ Ovaj sadržaj je dostupan samo korisnicima koji su platili, tako da ga NewPipe ne može strimovati ili preuzimati.
+ Istaknuto
+ Radio
+ Automatski (tema uređaja)
+ Odaberite svoju omiljenu noćnu temu — %s
+ Možete odabrati svoju omiljenu noćnu temu ispod
+ Ova opcija je dostupna samo ako je za temu odabrana %s
+ Preuzimanje je počelo
+ Sada možete odabrati tekst unutar opisa. Imajte na umu da stranica može treperiti i da linkovi možda neće biti dostupni za klikanje dok ste u načinu odabira.
+ Omogući odabir teksta u opisu
+ Onemogući odabir teksta u opisu
+ Kategorija
+ Oznake
+ Dozvola
+ Privatnost
+ Starosna granica
+ Jezik
+ Podrška
+ Domaćin
+ Sličice
+ Avatari koji su postavili profil
+ Avatari podkanala
+ Avatari
+ Baneri
+ Javno
+ Nije navedeno
+ Privatno
+ Unutrašnje
+ Pretplatnici
+ Zakačen komentar
+ Srce od strane kreatora
+ Otvori web stranicu
+ Tabletni način rada
+ Upaljeno
+ Ugašeno
+ Zadano za ExoPlayer
+ Obavještenja su onemogućena
+ Primajte obavještenja
+ Sada ste pretplaćeni na ovaj kanal
+ ,
+ Prikaži/Uključi sve
+ Strimovi koje program za preuzimanje još ne podržava nisu prikazani
+ Zvučni zapis bi već trebao biti prisutan u ovom toku
+ Odabrani tok nije podržan od strane eksternih plejera
+ Nema dostupnih audio tokova za vanjske uređaje za reprodukciju
+ Nema video tokova dostupnih za vanjske uređaje za reprodukciju
+ Odaberite kvalitet za vanjske uređaje za reprodukciju
+ Odaberite audio zapis za vanjske uređaje za reprodukciju
+ Nepoznati format
+ Nepoznat kvalitet
+ Nepoznato
+ Potpuno odgledano
+ Djelomično gledano
+ Nadolazeći
+ Sortiraj
+ Postavke ExoPlayera
+ Upravljajte nekim postavkama ExoPlayera. Ove promjene zahtijevaju ponovno pokretanje plejera da bi stupile na snagu
+ Koristite ExoPlayer-ovu rezervnu funkciju dekodera
+ Omogućite ovu opciju ako imate problema s inicijalizacijom dekodera, koja se vraća na dekodere nižeg prioriteta ako inicijalizacija primarnih dekodera ne uspije. Ovo može rezultirati lošijim performansama reprodukcije nego kada se koriste primarni dekoderi
+ Uvijek koristite ExoPlayer-ovo rješenje za podešavanje površine video izlaza
+ Ovo zaobilazno rješenje oslobađa i ponovo instancira video kodeke kada dođe do promjene površine, umjesto direktnog postavljanja površine na kodek. Već korištena od strane ExoPlayera na nekim uređajima s ovim problemom, ova postavka ima učinak samo na Androidu 6 i novijim verzijama.\n\nOmogućavanje ove opcije može spriječiti greške u reprodukciji prilikom prebacivanja trenutnog video playera ili prelaska na cijeli ekran
+ %1$s %2$s
+ original
+ sinhronizovano
+ opisni
+ sekundarni
+ Videozapisi
+ Snimke
+ Kratke hlače
+ Uživo
+ Kanali
+ Plejliste
+ Albuma
+ Sviđanja
+ O tome
+ Kartice kanala
+ Koje kartice se prikazuju na stranicama kanala
+ Otvori red za reprodukciju
+ Prikaz preko cijelog ekrana
+ Uključi/isključi orijentaciju ekrana
+ Prethodni tok
+ Sljedeći tok
+ Pokrenuti
+ Ponovna reprodukcija
+ Više opcija
+ Trajanje
+ Premotavanje unazad
+ Naprijed
+ Kvalitet slike
+ Odaberite kvalitet slika i da li će se slike uopće učitavati kako biste smanjili potrošnju podataka i memorije. Promjene brišu keš memoriju slika i u memoriji i na disku — %s
+ Ne učitavaj slike
+ Niska kvaliteta
+ Srednji kvalitet
+ Visoka kvaliteta
+ \?
+ Dijeli plejlistu
+ Podijeli s naslovima
+ Podijeli listu URL-ova
+ Podijeli kao privremenu YouTube plejlistu
+ - %1$s: %2$s
+ %1$s\n%2$s
+ Prikaži više
+ Prikaži manje
+ Postavke u izvozu koji se uvozi koriste ranjivi format koji je zastario od verzije NewPipe 0.27.0. Provjerite da izvoz koji se uvozi dolazi iz pouzdanog izvora i u budućnosti preferirajte korištenje samo izvoza dobivenih iz NewPipe 0.27.0 ili novije verzije. Podrška za uvoz postavki u ovom ranjivom formatu uskoro će biti potpuno uklonjena, a zatim stare verzije NewPipe-a više neće moći uvoziti postavke izvoza iz novih verzija.
+ Stranica SoundCloud Top 50 uklonjena
+ SoundCloud je ukinuo originalne Top 50 liste. Odgovarajuća kartica je uklonjena sa vaše glavne stranice.
+ Uklonjen je kombinovani prikaz trendova na YouTubeu
+ Trendovi u igrama
+ Trendovi podcasti
+ Popularni filmovi i serije
+ Popularna muzika
+ Unos izbrisan
+ HTTP greška 403 primljena od servera tokom reprodukcije, vjerovatno uzrokovana istekom URL-a za tokove ili zabranom IP adrese
+ HTTP greška %1$s primljena od servera tokom reprodukcije
+ HTTP greška 403 primljena od servera tokom reprodukcije, vjerovatno uzrokovana zabranom IP adrese ili problemima s deobfuskacijom URL-a za tokove
+ %1$s je odbio dati podatke, tražeći prijavu kako bi potvrdio da podnosilac zahtjeva nije bot.\n\nVašu IP adresu je možda privremeno zabranio %1$s, možete pričekati neko vrijeme ili preći na drugu IP adresu (na primjer uključivanjem/isključivanjem VPN-a ili prelaskom s WiFi-ja na mobilne podatke).
+
+ - %s pretplatnik
+ - %s pretplatnika
+ - %s pretplatnika
+
+
+ - %s pregled
+ - %s pregleda
+ - %s pregleda
+
+
+ - %s gledatelj
+ - %s gledatelja
+ - %s gledatelja
+
+
+ - %s slušatelj
+ - %s slušatelja
+ - %s slušatelja
+
+
+ - %s video
+ - %s videozapisa
+ - %s videozapisa
+
+
+ - %s novi tok
+ - %s nova toka
+ - %s novih tokova
+
+ O aplikaciji i pitanja
+
+ - %s preuzimanje je gotovo
+ - %s preuzimanja su gotova
+ - %s preuzimanja je gotovo
+
+
+ - Izbrisano %1$s preuzimanje
+ - Izbrisana %1$s preuzimanja
+ - Izbrisano %1$s preuzimanja
+
+
+ - %d sekunda
+ - %d sekunde
+ - %d sekundi
+
+
+ - %d minut
+ - %d minute
+ - %d minuta
+
+
+ - %d sat
+ - %d sata
+ - %d sati
+
+
+ - %d dan
+ - %d dana
+ - %d dana
+
+
+ - %d odabrana
+ - %d odabrane
+ - %d odabranih
+
+
+ - %s odgovor
+ - %s odgovora
+ - %s odgovora
+
+ YouTube je ukinuo kombinovanu stranicu s trendovima od 21. jula 2025. NewPipe je zamijenio zadanu stranicu s trendovima s trendovima uživo prijenosa.\n\nTakođer možete odabrati različite stranice s trendovima u \"Postavke > Sadržaj > Sadržaj glavne stranice\".
+ Ovaj sadržaj nije dostupan za trenutno odabranu zemlju sadržaja.\n\nPromijenite svoj odabir u \"Postavke > Sadržaj > Zadana zemlja sadržaja\".
+
diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml
index 123a5ef67..31183d15b 100644
--- a/app/src/main/res/values-ca/strings.xml
+++ b/app/src/main/res/values-ca/strings.xml
@@ -215,7 +215,7 @@
Controls de la velocitat de reproducció
Tempo
To
- Toca \"Cerca\" per començar.
+ Toqueu la lupa per començar.
Elimina l\'àudio en algunes resolucions
Reproductor d\'àudio extern
Emmagatzema les cerques localment
@@ -231,9 +231,6 @@
S\'està recuperant el reproductor després de l\'error
Bé, és lamentable.
Arrossegueu per reordenar la llista
- mil
- milions
- mil milions
Inicia
Feu un toc aquí per a més detalls
Defineix una carpeta de baixades més endavant als paràmetres
@@ -615,7 +612,6 @@
Pot seleccionar el seu tema fosc favorit aqui sota
Selecciona el teu tema fosc favorit — %s
Automàtic (tema del dispositiu)
- %s dóna aquesta raó:
Usuari suspes
El compte de l\'autor ha estat esborrat.
\nNewPipe no serà capaç de carregar aquest fil en el futur.
diff --git a/app/src/main/res/values-ckb/strings.xml b/app/src/main/res/values-ckb/strings.xml
index 649e6e73c..f0ddfb6e9 100644
--- a/app/src/main/res/values-ckb/strings.xml
+++ b/app/src/main/res/values-ckb/strings.xml
@@ -25,7 +25,6 @@
ژمارەی بەژداری نادیارە
ناتوانرێت لەسەر ئەو فایلهوه جێگیر بکرێت
پهڕه هەڵبژێرە
- ملیۆن
+١٠٠ ڤیدیۆیان
لێدهر
هاوردە
@@ -46,7 +45,6 @@
ئەمە لەسەر ڕێکخستنەکانی ئێستات جێگیر دەبێت.
پەیامەکانی نیوپایپ
نیوپایپ لەلایەن چەند خۆبەخشێکەوە دروستکراوە کە کاتهكانی خۆیان پێ بەخشیووە تاکو باشترین خزمەتگوزاریت پێشکەش بکەن. هیچ نەبێت بە کڕینی کوپێک قاوە یارمەتی گەشەپێدەرەکانمان بدە بۆ ئەوەی کاتی زیاتر تەرخان بکەین بۆ بەرەوپێشبردنی نیوپایپ.
- ملیار
گەڕانی پێشنیارکراوەکان
خێرا
فایل سڕایەوە
@@ -373,7 +371,6 @@
ناتوانرێت داببهزێنرێت
ناتوانرێت بە ڕاژەكهوە پەیوەست ببیت
لێدانی ڤیدیۆ، مهودا:
- هەزار
زۆرترین بەدڵ
سڕینەوە
جۆری بنەڕەتی ڤیدیۆ
@@ -599,7 +596,6 @@
ڕادیۆ
تایبەتکراو
ئهم بابهته تهنیا بۆ ئهو كهسانه بهردهسته كه پارهیان داوه ، بۆیه ناتوانرێت له نیوپایپهوه داببهزێنرێت.
- %s ئهم هۆكاره دابین دهكات:
ههژمار لهناوبراوه
ئهم ڤیدیۆیه تهنیا له وهشانی نایابی یوتوب میوزیك بهردهسته ، بۆیه ناتوانرێت له نیوپایپهوه داببهزێنرێت.
ئهمه تراكی SoundCloud Go+ ه ، لانی كهم له وڵاتهكهی تۆدا، ناتوانرێت لهلایهن نیوپایپهوه داببهزێنرێت.
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index c1f23457d..853b8c1cb 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -83,9 +83,7 @@
Určete prosím složku pro stahování později v nastavení
Co:\\nŽádost:\\nJazyk obsahu:\\nZemě obsahu:\\nJazyk aplikace:\\nSlužba:\\nČas GMT:\\nBalíček:\\nVerze:\\nVerze OS:
Vše
- tis.
Otevřít ve vyskakovacím okně
- mil.
Toto oprávnění je vyžadováno
\npro otevření ve vyskakovacím okně
Odstraňuje zvuk v některých rozlišeních
@@ -124,7 +122,6 @@
Oznámení pro NewPipe přehrávač
Žádné výsledky
Je tu sranda jak v márnici
- mld.
Žádní odběratelé
- %s odběratel
@@ -489,7 +486,7 @@
Prázdné jméno skupiny
Přejete si odstranit tuto skupinu?
- Nová
+ Nový
Novinky
Limit aktualizace novinek
Doba po poslední aktualizaci, po níž je odběr považován za zastaralý — %s
@@ -622,7 +619,6 @@
Vypnout výběr textu v popisu
Zapnout výběr textu v popisu
Nyní můžete vybrat v popisu text. Pamatujte, že v režimu výběru může stránka blikat a odkazy nemusí reagovat na kliknutí.
- %s udává teno důvod:
Účet uzavřen
Režim rychlého feedu o tom neposkytuje více informací.
Autorův účet byl uzavřen.
@@ -723,7 +719,7 @@
Klepnutím stáhnete %s
Rychlý režim
Používáte nejnovější verzi NewPipe
- Import nebo export odběrů z 3-tečkové nabídky
+ Importujte nebo exportujte odběry z 3tečkové nabídky
Tato možnost je dostupná pouze při vybraném motivu %s
Zrušení nastavení trvalého náhledu
Karta
@@ -848,4 +844,24 @@
Líbí se
Stránka SoundCloud Top 50 odstraněna
SoundCloud zrušil původní žebříčky Top 50. Příslušná karta byla odstraněna z vaší hlavní stránky.
+ YouTube kombinované trendy odstraněny
+ YouTube ukončil provoz kombinované stránky s trendy k 21. červenci 2025. NewPipe nahradil výchozí stránku s trendy stránkou s trendy živými přenosy.\n\nMůžete také vybrat různé stránky s trendy v části „Nastavení > Obsah > Obsah úvodní stránky“.
+ Populární hry
+ Populární podcasty
+ Populární filmy a seriály
+ Populární hudba
+ %s tis.
+ %s mil.
+ %s mld.
+ Pro používání Popup Playeru vyberte v následující nabídce nastavení Androidu možnost %1$s a povolte %2$s.
+ \"Povolit zobrazení přes jiné aplikace\"
+ Vymazat soubor
+ Vymazat položku
+ Položka vymazána
+ Ukončení účtu\n\n%1$s uvádí tento důvod: %2$s
+ Během přehrávání byla ze serveru přijata chyba HTTP 403, pravděpodobně způsobená vypršením platnosti streamingové adresy URL nebo zákazem IP adresy
+ Chyba HTTP %1$s obdržená ze serveru během přehrávání
+ Chyba HTTP 403 obdržená od serveru během přehrávání, pravděpodobně způsobená zákazem IP adresy nebo problémy s deobfuskací streamovací adresy URL
+ %1$s odmítl poskytnout data, žádá o přihlášení k potvrzení, že žadatel není bot.\n\nVaše IP adresa mohla být dočasně zakázána %1$s, můžete nějakou dobu počkat nebo přepnout na jinou IP adresu (například zapnutím/vypnutím VPN nebo přepnutím z WiFi na mobilní data).
+ Tento obsah není pro aktuálně vybranou zemi obsahu dostupný.\n\nZměňte výběr v nabídce \"Nastavení > Obsah > Výchozí země obsahu\".
diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml
index cecdcc4fe..78f08ee85 100644
--- a/app/src/main/res/values-da/strings.xml
+++ b/app/src/main/res/values-da/strings.xml
@@ -232,7 +232,7 @@
Mest Afspillet
Indhold af hovedside
Hvilke faner vises på hovedsiden
- Tom Side
+ Tom side
Kioskside
Kanalside
Vælg en kanal
@@ -305,9 +305,6 @@
Stop
Hændelser
Ikke andet end fårekyllinger her
- t
- mio.
- mia.
- %s abonnent
- %s abonnenter
@@ -557,7 +554,6 @@
Dette indhold er privat, så det kan ikke streames eller hentes af NewPipe.
Nyligt tilføjede
Fremhævede
- %s giver denne grund:
- %s lytter
- %s lyttere
@@ -829,4 +825,20 @@
Kanalgruppeside
Vælg en feed-gruppe
Ingen feed-gruppe oprettet endnu
+ Søg %1$s
+ Søg %1$s (%2$s)
+ For at kunne bruge pop op-afspilleren skal du vælge %1$s i følgende Android-indstillingsmenu og aktivere %2$s.
+ “Tillad visning over andre apps”
+ %sK
+ %sM
+ %sB
+ Slet fil
+ Kontoen er blevet lukket\n\n%1$s angiver følgende årsag: %2$s
+ Likes
+ SoundCloud Top 50-siden fjernet
+ SoundCloud har udfaset de oprindelige Top 50-hitlister. Den tilhørende fane er blevet fjernet fra din hovedside.
+ YouTube kombineret trending fjernet
+ YouTube har udfaset den kombinerede trending-side pr. 21. juli 2025. NewPipe har erstattet standardsiden for trending med trending livestreams.\n\nDu kan også vælge andre trending-sider under \"Indstillinger > Indhold > Indhold på hovedsiden\".
+ Gaming-trends
+ Trending podcasts
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 1f06121a8..b36b8555b 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -69,9 +69,6 @@
Fehlerbericht
Löschen
Prüfsumme
- Tsd.
- Mio.
- Mrd.
Dateiname
Fehler
Bitte warten …
@@ -630,7 +627,6 @@
Du wirst jedes Mal gefragt werden, wohin der Download gespeichert werden soll
Fehler beim Laden des Feeds
Konnte Feed für \'%s\' nicht laden.
- %s gibt diesen Grund an:
An
Tablet-Modus
Aus
@@ -834,4 +830,24 @@
Gefällt mir
SoundCloud-Top-50-Seite entfernt
SoundCloud hat die ursprünglichen Top-50-Charts abgeschafft. Der entsprechende Tab wurde von deiner Hauptseite entfernt.
+ %sMio.
+ %sMrd.
+ %sTsd.
+ Gaming-Trends
+ Beliebte Filme und Shows
+ Beliebte Musik
+ Beliebte Podcasts
+ YouTube hat die kombinierten „beliebten Seiten“ entfernt
+ YouTube hat die kombinierte Trending-Seite ab dem 21. Juli 2025 eingestellt. NewPipe hat die Standard-Trending-Seite durch die Trending-Livestreams ersetzt.\n\nDu kannst auch verschiedene Trendseiten unter „Einstellungen > Inhalt > Inhalt der Hauptseite“ auswählen.
+ Um den Pop-up-Player zu verwenden, bitte in den folgenden Android-Einstellungen %1$s auswählen und %2$s aktivieren.
+ „Über anderen Apps einblenden“
+ Datei löschen
+ Eintrag löschen
+ Eintrag gelöscht
+ Konto geschlossen\n\n%1$s gibt folgenden Grund an: %2$s
+ HTTP-Fehler 403 vom Server während der Wiedergabe erhalten, wahrscheinlich verursacht durch Ablauf der Streaming-URL oder eine IP-Sperre
+ HTTP-Fehler %1$s vom Server während der Wiedergabe erhalten
+ HTTP-Fehler 403 vom Server während der Wiedergabe erhalten, wahrscheinlich verursacht durch eine IP-Sperre oder Probleme beim Entschlüsseln der Streaming-URL
+ %1$s hat die Datenbereitstellung verweigert und verlangt eine Anmeldung, um zu bestätigen, dass es sich bei dem Anfragenden nicht um einen Bot handelt.\n\nDeine IP-Adresse wurde möglicherweise vorübergehend von %1$s gesperrt. Du kannst einige Zeit warten oder zu einer anderen IP-Adresse wechseln (z. B. durch Ein- und Ausschalten eines VPNs oder durch Wechseln von WLAN zu mobilen Daten).
+ Dieser Inhalt ist für das aktuell ausgewählte Land des Inhalts nicht verfügbar.\n\nÄndere die Auswahl unter „Einstellungen > Inhalt > Bevorzugtes Land des Inhalts“.
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index 84da93a0f..02bf75b30 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -41,7 +41,6 @@
Μικρογραφία εικόνας προφίλ του χρήστη
Like
Dislike
- δισ/ρια
Άνοιγμα σε αναδυόμενο παράθυρο
Εγγραφή
Εγγεγραμμένος
@@ -169,8 +168,6 @@
Δεν υπάρχει τίποτα εδώ
Σύρετε για ταξινόμηση
Προσπάθεια εκ νέου
- χιλ.
- εκ/ρια
Κανένας συνδρομητής
- %s συνδρομητής
@@ -611,7 +608,6 @@
Ενεργοποίηση επιλογής κειμένου στην περιγραφή
Τώρα μπορείτε να επιλέξετε κείμενο εντός της περιγραφής. Σημειώστε ότι, η σελίδα μπορεί να παρουσιάζει αστάθεια κατά τη διάρκεια της κατάστασης επιλογής κειμένου.
Ανοικτή ιστοσελίδα
- Το %s παρέχει αυτή την αιτία:
Ο λογαριασμός διαγράφηκε
Η κατάσταση γρήγορης τροφοδοσίας δεν παρέχει περισσότερες πληροφορίες.
Ο λογαριασμός του δημιουργού έχει διαγραφεί.
@@ -831,7 +827,27 @@
Σελίδα καναλιού ομάδας
Αναζήτηση %1$s
Αναζήτηση %1$s (%2$s)
- Likes
+ Μου αρέσει
Η σελίδα των SoundCloud Top 50 αφαιρέθηκε
Το SoundCloud έχει καταργήσει τα αρχικά charts με τα Top 50. Η αντίστοιχη καρτέλα έχει αφαιρεθεί από την κύρια σελίδα σας.
+ Οι συνδυασμένες τάσεις στο YouTube καταργήθηκαν
+ Το YouTube έχει καταργήσει τη συνδυασμένη σελίδα με τάσεις από την 21 Ιουλίου 2025. Το NewPipe αντικατέστησε την προεπιλεγμένη σελίδα τάσεων με τις ζωντανές ροές τάσεων.\n\nΜπορείτε επίσης να επιλέξετε διαφορετικές σελίδες με τάσεις στις \"Ρυθμίσεις > Περιεχόμενο > Περιεχόμενο κύριας σελίδας\".
+ Τάσεις παιχνιδιών
+ Τάσεις podcasts
+ Τάσεις ταινιών και εκπομπών
+ Μουσικές τάσεις
+ %sK
+ %sM
+ %sB
+ Για να χρησιμοποιήσετε το Αναδυόμενο Πρόγραμμα Αναπαραγωγής, επιλέξτε %1$s στο ακόλουθο μενού ρυθμίσεων Android και ενεργοποιήστε το %2$s.
+ «Να επιτρέπεται η εμφάνιση πάνω από άλλες εφαρμογές»
+ Διαγραφή αρχείου
+ Διαγραφή καταχώρησης
+ Η καταχώρηση διαγράφηκε
+ Ο λογαριασμός έκλεισε\n\n%1$s παρέχει αυτήν την αιτία: %2$s
+ Σφάλμα HTTP 403 που ελήφθη από τον διακομιστή κατά την αναπαραγωγή, πιθανώς λόγω λήξης διεύθυνσης URL ροής ή αποκλεισμού IP
+ Σφάλμα HTTP %1$s ελήφθη από τον διακομιστή κατά την αναπαραγωγή
+ Σφάλμα HTTP 403 ελήφθη από τον διακομιστή κατά την αναπαραγωγή, πιθανώς λόγω αποκλεισμού IP ή προβλημάτων απεμπλοκής URL ροής
+ Ο %1$s αρνήθηκε να παράσχει δεδομένα, ζητώντας σύνδεση για να επιβεβαιώσει ότι ο αιτών δεν είναι bot.\n\nΗ IP σας ενδέχεται να έχει αποκλειστεί προσωρινά από τον %1$s. Μπορείτε να περιμένετε λίγο ή να αλλάξετε IP (για παράδειγμα, ενεργοποιώντας/απενεργοποιώντας ένα VPN ή αλλάζοντας από WiFi σε δεδομένα κινητής τηλεφωνίας).
+ Αυτό το περιεχόμενο δεν είναι διαθέσιμο για την τρέχουσα επιλεγμένη χώρα περιεχομένου.\n\nΑλλάξτε την επιλογή σας από \"Ρυθμίσεις > Περιεχόμενο > Προεπιλεγμένη χώρα περιεχομένου\".
diff --git a/app/src/main/res/values-en-rGB/strings.xml b/app/src/main/res/values-en-rGB/strings.xml
index 8b022bcff..1a80eefd9 100644
--- a/app/src/main/res/values-en-rGB/strings.xml
+++ b/app/src/main/res/values-en-rGB/strings.xml
@@ -84,4 +84,14 @@
Okay
Open in browser
No stream player found (you can install VLC to play it).
+ Yes
+ No
+ Mark as watched
+ Open in popup mode
+ Open with
+ Share
+ Download
+ Download stream file
+ Search
+ Settings
diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml
index 1da4d536c..3dde69618 100644
--- a/app/src/main/res/values-eo/strings.xml
+++ b/app/src/main/res/values-eo/strings.xml
@@ -261,9 +261,6 @@
- %s spekto
- %s spektoj
- k
- M
- Mrd
Pri NewPipe
Eksteraj permesiloj
© %1$s de %2$s sub %3$s
@@ -507,7 +504,6 @@
Ŝaltita
Etikedoj
Elŝutado komenciĝis
- %s donas tiun kialon:
Tiu enaĵo ne disponeblas en via lando.
Freŝaj
De %s
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 610d900ec..72d1f58b5 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -81,9 +81,6 @@
Qué:\\nSolicitud:\\nIdioma del contenido:\\nPaís del contenido:\\nIdioma de la aplicación:\\nServicio:\\nMarca de tiempo:\\nPaquete:\\nVersión:\\nVersión del SO:
Negro
Todo
- k
- M
- MM
Abrir en modo emergente
Se necesita este permiso
\npara abrir en modo emergente
@@ -614,7 +611,6 @@
Deshabilitar la selección de texto de la descripción
Habilitar la selección de texto de la descripción
Ahora puede seleccionar el texto dentro de la descripción. Note que la página puede parpadear y los links no serán cliqueables mientras está en el modo de selección.
- %s da esta razón:
No fue posible cargar el feed por \'%s\'.
Cuenta cancelada
El modo de muro rápido no arroja más información sobre esto.
@@ -833,4 +829,29 @@
Selecciona un grupo de feed
Aún no se ha creado ningún grupo de feed
Página de grupo de canales
+ Buscar %1$s
+ Buscar %1$s (%2$s)
+ Me gusta
+ Página Top 50 de SoundCloud eliminada
+ SoundCloud ha descontinuado las listas originales del Top 50. La pestaña correspondiente se ha eliminado de la página principal.
+ YouTube tendencias combinadas eliminado
+ YouTube ha descontinuado la página de tendencias combinadas a partir del 21 de julio de 2025. NewPipe reemplazó la página de tendencias predeterminada con tendencias en directo.\n\nTambién puedes seleccionar diferentes páginas de tendencias en \"Ajustes > Contenido > Contenido de la página principal\".
+ Tendencias videojuegos
+ Tendencias pódcasts
+ Tendencias películas y programas
+ Tendencias música
+ “Permitir mostrar sobre otras aplicaciones”
+ Eliminar archivo
+ %sM
+ %sM
+ Eliminar entrada
+ Cuenta cancelada\n\n%1$s proporciona esta razón: %2$s
+ Entrada eliminada
+ Error HTTP 403 recibido del servidor durante la reproducción, probablemente causado por la expiración de la URL de transmisión o una prohibición de IP
+ Error HTTP %1$s recibido del servidor durante la reproducción
+ Error HTTP 403 recibido del servidor durante la reproducción, probablemente causado por una prohibición de IP o problemas de desofuscación de la URL de transmisión
+ %1$s se negó a proporcionar datos y solicitó un inicio de sesión para confirmar que el solicitante no es un bot.\n\nEs posible que tu IP haya sido bloqueada temporalmente por %1$s. Puedes esperar un tiempo o cambiar a una IP diferente (por ejemplo, habilitando o deshabilitando una VPN, o cambiando de WiFi a datos móviles).
+ %sMM
+ Este contenido no está disponible para el país seleccionado actualmente.\n\nCambia tu selección en «Ajustes > Contenido > País predefinido del contenido».
+ Para usar el reproductor emergente, seleccione %1$s en el siguiente menú de la configuración de Android y habilite %2$s.
diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml
index af8cfde88..05f4cf505 100644
--- a/app/src/main/res/values-et/strings.xml
+++ b/app/src/main/res/values-et/strings.xml
@@ -154,9 +154,6 @@
Video
Audio
Proovi uuesti
- tuh
- mln
- mld
Tellijaid pole
- %s tellija
@@ -565,7 +562,6 @@
Näita pisipilte
Kasuta pisipilti nii lukustusvaate kui teavituste taustana
Kasutajakonto on suletud
- %s toob põhjuseks:
Võimalda valida kirjelduse teksti
Ära võimalda valida kirjelduse teksti
Kategooria
@@ -607,7 +603,7 @@
Hangi võimalusel spetsiaalsest voost
Kiirvoo režiim ei paku selle kohta täiendavat teavet.
Autori konto on suletud. \nTulevikus ei saa NewPipe seda meediavoogu laadida. \nKas soovid tühistada selle kanali tellimuse?
- Voo \'%s\' laadimine nurjus.
+ Voo \'%s\' laadimine ei õnnestnud.
Via voo laadimisel
Värskenda alati
Aeg pärast viimast värskendust, mille möödudes loetakse tellimus aegunuks — %s
@@ -819,4 +815,24 @@
Meeldimisi
SoundCloudi „Top 50“ leht on eemaldatud
SoundCloud on lõpetanud oma algse „Top 50“ edetabeli pidamise. Seega on ka vastav vahekaart meie rakenduse põhivaatest eemaldatud.
+ YouTube\'i kombineeritud populaarsust koguvad videovoog on eemaldatud
+ YouTube on alates 21.07.25 lõpetanud ühendatud populaarsust koguvate videote lehe kasutamise. Mistõttu ka NewPipe on asendanud vaikimisi populaarsust koguvate videote lehe sarnase otse-eetri lehega.\n\n„Seadistused -> Sisu -> Avalehe sisu“ alt saad ka muid sarnaseid lehti seadistada.
+ Populaarsust koguvad taskuhäälingud
+ Populaarsust koguvad filmid ja telesarjad
+ Populaarsust koguv muusika
+ Populaarsust koguvad mängud
+ %s tuh
+ %s mln
+ %s mld
+ Kasutamaks meediaesitajat hüpikaknas palun vali järgnevast Androidi seadistuste valikust „%1$s“ ja lülita sisse „%2$s“.
+ Luba kuvamine teiste rakenduste peal
+ Kustuta fail
+ Kustuta kirje
+ Kirje on kustutatud
+ Kasutajakonto on suletud\n\n%1$s on märkinud põhjuseks: %2$s
+ Esitamise ajal lisas server andmevoogu HTTP oleku 403 ning tavaliselt tähendab see, et voogedastuse võrguaadress on aegunud või sinu seadme IP-aadress on keelatud
+ Esitamise ajal lisas server andmevoogu HTTP oleku %1$s
+ Esitamise ajal lisas server andmevoogu HTTP oleku 403 ning tavaliselt tähendab see, et sinu seadme IP-aadress on keelatud või voogedastuse võrguaadressi hägustamisvastastes meetmetes on viga
+ See sisu pole saadaval hetkel kehtvas riigis.\n\nRiiki saad muuta: Seadistused > Sisu > Sisu vaikimisi riik.
+ %1$s keeldus andmete edastamisest ning eeldab sisselogimist tuvastamaks, et tegemist pole robotiga.\n\nLisaks võib olla juhtunud, et %1$s on lisanud sinu seadme ip-aadressi ajutisse keelunimekirja. Sa võid oodata natuke aega või vahetada võrguühendus viisi (näiteks lülitades VPN sisse/välja või kasutades WiFi asemel mobiilset internetiühendust).
diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml
index 16054d9ae..5c963d6b7 100644
--- a/app/src/main/res/values-eu/strings.xml
+++ b/app/src/main/res/values-eu/strings.xml
@@ -84,9 +84,6 @@
Bideoa
Audioa
Saiatu berriro
- k
- M
- MM
Hasi
Pausatu
Ezabatu
@@ -618,7 +615,6 @@
Non gorde galdetuko zaizu deskarga bakoitzean
Ez da deskargatzeko karpetarik ezarri oraindik, aukeratu lehenetsitako deskargatzeko karpeta orain
Pribatutasuna
- %s arrazoi hau ematen du:
Kontua ezabatu da
Jario azkarrak ez du honi buruz informazio gehiagorik ematen.
Adin muga
diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml
index 3bba8efb8..403fb4c11 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -148,9 +148,6 @@
خطایی رخ داد: %1$s
جریانی برای بارگیری در دسترس نیست
بدون نتیجه
- K
- M
- B
- %s مشترک
- %s مشترک
@@ -629,7 +626,6 @@
\nنیوپایپ قادر به بار کردن این خوراک در آینده نیست.
\nمیخواهید اشتراک این کانال را لغو کنید؟
حالت خوراک سریع، اطَلاعات بیشتری در این باره نمیدهد.
- %s این دلیل را آورد:
پیشنمایش بندانگشتی نوار جویش
قلبشده به دست ایجادگر
پیشنهادهای جستوجوی محلّی
diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml
index 20734dd26..22c1fab12 100644
--- a/app/src/main/res/values-fi/strings.xml
+++ b/app/src/main/res/values-fi/strings.xml
@@ -102,9 +102,6 @@
Video
Ääni
Toista uudelleen
- t.
- milj.
- bilj.
Ei tilaajia
- %s tilaaja
@@ -595,7 +592,6 @@
Yöteema
Poista käytöstä tekstinvalinta kuvauskentän sisältä
Voit nyt valita tekstin kuvauskentän sisältä. Huomioithan, että valintatilan aikana sivu voi vilkkua ja linkit eivät ehkä ole klikattavia.
- %s tuo tämän syyn:
Säätövivun kuvakkeen esikatselu
Poista median tunnelointi käytöstä, jos havaitset mustan näyttöruudun tai änkytystä videon toistossa.
Poista median tunnelointi käytöstä
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 9a9590a07..eb28d0e21 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -87,8 +87,6 @@
Lecture en mode flottant
Désactivés
Quoi :\\nRequest :\\nContent Language :\\nContent Country :\\nApp Language :\\nService :\\nGMT Time :\\nPackage :\\nVersion :\\nOS version :
- k
- M
Cette autorisation est nécessaire pour
\nutiliser le mode flottant
Arrière-plan
@@ -100,7 +98,6 @@
Mémoriser les propriétés de la fenêtre flottante
Mémoriser les dernières taille et position de la fenêtre flottante
Effacer
- G
Le son peut être absent à certaines définitions
Suggestions de recherche
Sélectionner les suggestions à afficher lors d’une recherche
@@ -210,15 +207,15 @@
Chargement du contenu demandé
Importer la base de données
Exporter la base de données
- Remplace votre historique, vos abonnements, vos listes de lecture et (en option) vos paramètres
- Exporte l’historique, les abonnements, les listes de lecture et les paramètres
+ Remplace votre historique, vos abonnements, vos playlists et (en option) vos paramètres
+ Exporte l’historique, les abonnements, les playlists et les paramètres
Exporté
Importé
Fichier ZIP non valide
Avertissement : impossible d’importer tous les fichiers.
Cela effacera vos paramètres actuels.
Afficher les informations
- Listes de lecture enregistrées
+ Playlists enregistrées
Ajouter à
Glisser pour réordonner
Créer
@@ -227,17 +224,17 @@
Dernière lecture
Vidéos les plus vues
Toujours demander
- Nouvelle liste de lecture
+ Nouvelle playlist
Renommer
Nom
- Ajouter à la liste de lecture
- Définir comme miniature de la liste de lecture
- Enregister la liste de lecture
+ Ajouter à la playlist
+ Définir comme miniature de la playlist
+ Enregister la playlist
Supprimer le signet
- Voulez-vous supprimer cette liste de lecture \?
- Liste de lecture créée
- Ajouté à la liste de lecture
- Miniature de la liste de lecture changée.
+ Voulez-vous supprimer cette playlist ?
+ Playlist créée
+ Ajouté à la playlist
+ Miniature de la playlist changée.
Aucun sous-titre
Ajuster
Zoomer
@@ -321,7 +318,7 @@
Aucune limite
Limiter la définition lors de l’utilisation des données mobiles
Chaînes
- Listes de lecture
+ Playlists
Morceaux
Utilisateurs
Accélérer pendant les silences
@@ -358,7 +355,7 @@
Téléchargement échoué
Délai de connexion expiré
Conférences
- ajouté à la liste de lecture
+ ajouté à la playlist
Générer un nom unique
Écraser
Un fichier avec ce nom existe déjà
@@ -389,7 +386,7 @@
Aucun commentaire
Impossible de charger les commentaires
Fermer
- Reprendre la liste de lecture
+ Reprendre la playlist
Effacer les données
Fichier déplacé ou supprimé
impossible d’écraser le fichier
@@ -525,8 +522,7 @@
\nActivez « %1$s » dans les paramètres si vous voulez la voir.
Supprimer les vidéos visionnées
Oui ainsi que les vidéos partiellement visionnées
- Les vidéos qui ont été visionnées avant et après avoir été ajoutées à la liste de lecture seront supprimées.
-\nÊtes-vous certain(e) \? Cette action est irréversible !
+ Les vidéos qui ont été visionnées avant et après avoir été ajoutées à la playlist seront supprimées. \nÊtes-vous certain(e) ? Cette action est irréversible !
Supprimer les vidéos visionnées \?
Miniature de l\'avatar de la chaine
De %s
@@ -535,9 +531,9 @@
Afficher la date originelle sur les items
Activer le « Mode restreint » de YouTube
Afficher uniquement les abonnements non groupés
- Page des listes de lecture
- Aucune liste de lecture encore enregistrée
- Sélectionner une liste de lecture
+ Page des playlists
+ Aucune playlist encore enregistrée
+ Sélectionner une playlist
Veuillez vérifier si un ticket concernant votre problème existe déjà. Lorsque vous créez des tickets dupliqués, cela nous prend du temps que nous pourrions passer à résoudre effectivement le problème.
Signaler sur GitHub
Copier le rapport formaté
@@ -623,7 +619,6 @@
Étiquettes
Catégorie
Vous pouvez maintenant sélectionner du texte à l’intérieur de la description. Notez que la page peut scintiller et que les liens peuvent ne pas être cliquables en mode sélection.
- %s indique le motif :
Aucun dossier de téléchargement n’est défini pour le moment, sélectionnez le dossier de téléchargement par défaut
Ouvrir le site web
Compte résilié
@@ -728,7 +723,7 @@
Appuyez pour télécharger %s
Échec de la copie dans le presse-papiers
Cette option est disponible seulement si %s est sélectionné pour le thème
- Les listes de lecture grisées contiennent déjà cet élément.
+ Les playlists grisées contiennent déjà cet élément.
Carte
Utile si, par exemple, vous utilisez un casque avec des boutons dysfonctionnels
Effacer les doublons
@@ -789,7 +784,7 @@
Albums
Qualité moyenne
Bannières
- Listes de lecture
+ Playlists
Plus d’options
Miniatures
Pistes
@@ -805,7 +800,7 @@
Partager une liste d\'URLs
%1$s
\n%2$s
- Partager la liste de lecture
+ Partager la playlist
- %1$s : %2$s
Choisir quels onglets seront visibles sur les pages de chaîne
Changer l’orientation de l’écran
@@ -840,14 +835,34 @@
Pas assez d\'espace disponible sur l\'appareil
Les paramètres de l\'export en cours d\'importation utilisent un format vulnérable qui a été déprécié depuis NewPipe 0.27.0. Assurez-vous que l\'export en cours d\'importation provient d\'une source fiable. Privilégiez les exports obtenues à partir de NewPipe 0.27.0 ou des versions plus récentes à l\'avenir. Le support pour l\'importation des paramètres dans ce format vulnérable sera bientôt complètement supprimé et les anciennes versions de NewPipe ne pourront plus importer les paramètres des exports des nouvelles versions.
secondaire
- Partager comme liste de lecture YouTube temporaire
- Listes de lecture
+ Partager comme playlist YouTube temporaire
+ Playlists
Sélectionnez un groupe de flux
- Aucun groupe de flux n\'a encore été créé
+ Encore aucun groupe de flux créé
Page du groupe de chaînes
Rechercher %1$s
Rechercher %1$s (%2$s)
- Likes
+ J’aime
Page SoundCloud Top 50 supprimée
SoundCloud a abandonné le classement original du Top 50. L\'onglet correspondant a été supprimé de votre page d\'accueil.
+ Suppression des tendances combinées sur YouTube
+ YouTube a supprimé la page des tendances combinées depuis le 21 juillet 2025. NewPipe a remplacé la page des tendances par défaut par les diffusions en direct les plus populaires.\n\nVous pouvez également sélectionner différentes pages de tendances dans « Paramètres > Contenu > Contenu de la page principale ».
+ Tendances jeu vidéo
+ Tendances podcasts
+ Tendances films et séries
+ Tendances musique
+ %sK
+ %sM
+ %sB
+ Pour utiliser le lecteur contextuel, veuillez sélectionner %1$s dans le menu des paramètres Android suivant et activer %2$s.
+ « Autoriser l\'affichage sur d\'autres applications »
+ Supprimer le fichier
+ Supprimer l\'entrée
+ Entrée supprimée
+ Compte fermé\n\n%1$s fournit la raison suivante : %2$s
+ Erreur HTTP 403 reçue du serveur pendant la lecture, probablement causée par l\'expiration de l\'URL de streaming ou une interdiction d\'IP
+ Erreur HTTP %1$s reçue du serveur pendant la lecture
+ Erreur HTTP 403 reçue du serveur pendant la lecture, probablement causée par un bannissement d\'IP ou des problèmes de désobfuscation de l\'URL de streaming
+ %1$s a refusé de fournir des données et a demandé un identifiant pour confirmer que le demandeur n\'est pas un robot.\n\nVotre adresse IP a peut-être été temporairement bannie par %1$s. Vous pouvez patienter un peu ou changer d\'adresse IP (par exemple en activant/désactivant un VPN, ou en passant du Wi-Fi aux données mobiles).
+ Ce contenu n\'est pas disponible pour le pays actuellement sélectionné.\n\nModifiez votre sélection dans « Paramètres > Contenu > Pays par défaut ».
diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml
index d345b9385..aacaf9288 100644
--- a/app/src/main/res/values-gl/strings.xml
+++ b/app/src/main/res/values-gl/strings.xml
@@ -158,9 +158,6 @@
Vídeo
Audio
Tentar de novo
- k
- M
- B
Ningún subscrito
- %s subscrito
@@ -557,7 +554,6 @@
Agora pode seleccionar o texto na descrición. Teña en conta que a páxina pode cintilar e as ligazóns poden non ser clicábeis no modo selección.
Automático (Tema do dispositivo)
Radio
- %s dá este motivo:
Este contido non está dispoñíbel no seu país.
Capítulos
Recentes
diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml
index a09c0da03..c35281207 100644
--- a/app/src/main/res/values-he/strings.xml
+++ b/app/src/main/res/values-he/strings.xml
@@ -112,9 +112,6 @@
סרטון
שמע
ניסיון חוזר
- אלפ.
- מיל.
- מיליארד
אין מנויים
- מנוי אחד
@@ -598,7 +595,7 @@
פתיחה באמצעות
אין יישומון על המכשיר שלך שיכול לפתוח את זה
להקריס את היישומון
- תוכן זה זמין רק למשתמשים ששילמו, לכן לא ניתן להזרים או להוריד אותו עם NewPipe.
+ התוכן הזה זמין רק למשתמשים ששילמו, לכן לא ניתן להזרים או להוריד אותו עם NewPipe.
סרטון זה זמין רק למנויי YouTube Music Premium, לכן לא ניתן להזרים או להוריד אותו עם NewPipe.
זה תוכן פרטי, לכן לא ניתן להזרים או להוריד אותו עם NewPipe.
רצועה זו של SoundCloud Go+ מוגבלת, לפחות במדינה שלך, לכן לא ניתן להזרים או להוריד אותה עם NewPipe.
@@ -635,7 +632,6 @@
\nל־NewPipe לא תהיה אפשרות להוריד את ההזנה הזאת בעתיד.
\nלהסיר את המינוי מהערוץ הזה\?
פתיחת האתר
- %s מספק את הסיבה הבאה:
החשבון הושמד
מצב ההזנה המהירה לא מספק מידע נוסף על כך.
לא ניתן לטעון את ההזנה עבור ‚%s’.
@@ -859,4 +855,26 @@
חיפוש ב־%1$s
חיפוש ב־%1$s (%2$s)
לייקים
+ חשבון הושמד\n\n%1$s מספק את הסיבה הבאה: %2$s
+ כדי להשתמש בנגן צף, נא לבחור ב־%1$s בתפריט ההגדרות הבא של Android ולהפעיל את %2$s.
+ „תמיד להציג מעל יישומונים אחרים”
+ %s אלף
+ %s מיליון
+ %s מיליארד
+ המובילים המשולבים של YouTube הוסרו
+ מחיקת קובץ
+ מחיקת רשומה
+ עמוד 50 המובילים ב־SoundCloud הוסר
+ מגמות במשחקים
+ פודקאסטים מובילים
+ סרטים וסדרות מובילים
+ מוזיקה מובילה
+ הרשומה נמחקה
+ SoundCloud הפסיקו את מצעדי 50 הלהיטים המקוריים. הלשונית התואמת הוסרה מהעמוד הראשי שלך.
+ ב־YouTube הושבת עמוד המובילים המשולב החל מ־21 ביולי 2025. NewPipe החליפה את עמוד המובילים המוגדר כברירת מחדל בשידורים חיים מובילים.\n\nניתן גם לבחור עמודי מובילים שונים תחת „הגדרות > תוכן > תוכן הדף הראשי”.
+ שגיאת HTTP 403 שהתקבלה מהשרת בזמן השמעה, ככל הנראה נגרמת עקב פקיעת כתובת URL של סטרימינג או חסימת IP
+ שגיאת HTTP %1$s התקבלה מהשרת בזמן הניגון
+ שגיאת HTTP 403 שהתקבלה מהשרת בזמן הניגון, ככל הנראה נגרמה עקב חסימת IP או בעיות בהסרת ערפול כתובת תזרים
+ %1$s סירב לספק נתונים, וביקש התחברות כדי לאשר שהמבקש אינו בוט.\n\nכנראה שה־IP שלך נחסם זמנית על ידי %1$s, ניתן להמתין זמן מה או לעבור ל־IP אחר (לדוגמה על ידי הפעלה/כיבוי של VPN, או על ידי מעבר מרשת אלחוטית לתקשורת נתונים סלולרית).
+ תוכן זה אינו זמין עבור מדינת התוכן שנבחרה כעת.\n\nניתן לשנות את בחירתך דרך „הגדרות > תוכן > מדינת תוכן ברירת מחדל”.
diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml
index 7d405bcef..d2e6a422e 100644
--- a/app/src/main/res/values-hi/strings.xml
+++ b/app/src/main/res/values-hi/strings.xml
@@ -74,7 +74,7 @@
देखे गए वीडियोज़ की सूची रखें
प्लेबैक फिर से शुरू करें
रुकावटें (जैसे कि फ़ोन कॉल) खत्म होने के बाद वीडियो प्ले जारी रखें
- \'अगले\' और \'सबंधित\' वीडियो दिखाएं
+ \'अगला\' और \'संबंधित\' वीडियो दिखाएं
\"कतार में जोड़ने के लिए स्पर्श बनाये रखें\" दिखाएं
जब बैकग्राउंड और पॉपअप बटन वीडियो के विवरण पन्ने में दबाई जाए तो सलाह दिखाएं
असमर्थित URL
@@ -93,7 +93,7 @@
बंद किया
साफ करें
उत्तम रिजॉल्युशन
- वापिस
+ अन-डू करें
सभी प्ले करें
न्यूपाइप की नोटीफिकेशन
न्यूपाइप के प्लेयर के लिए नोटीफिकेशन
@@ -104,7 +104,7 @@
वैबसाइट parse नहीं हो सकी
विषय वस्तु उपलब्ध नहीं है
डाउनलोड मेनू स्थापित नहीं किया जा सका
- APP/UI करैश हो गई
+ ऐप/UI करैश हो गई
इस वीडियो को चलाने में असफल हुए
अनचाही वीडियो प्लेयर त्रुटी आयी है
वीडियो प्लेयर त्रुटी से ठीक हो रहा है
@@ -126,9 +126,6 @@
वीडियो
ऑडियो
फिर से कोशिश करें
- हज़ार
- मिलियन
- अरब
कोई सब्सक्राइबर नहीं
- %s सब्सक्राइबर
@@ -394,7 +391,7 @@
प्लेबैक स्थानों को मिटाएं
सारे प्लेबैक स्थानों को मिटाता है
सारे प्लेबैक स्थानों को मिटाएं\?
- निपटान के बाद खंड या गतिविधि जीवन चक्र के बाहर अविभाज्य आरएक्स अपवादों की रिपोर्टिंग को बलपूर्वक लागू करें
+ हैंडलिंग के बाद फ्रैगमेंट या एक्टिविटी लूप के बाहर अनहैंडल्ड Rx एक्सेप्शन की रिपोर्टिंग को बलपूर्वक लागू करें
साउंडक्लाउड प्रोफाइल निर्यात करने के लिए आईडी या युआरएल दीजिये:
\n
\n1. अपने वेब ब्राउज़र में \"डेस्कटॉप मोड\" चालू करें (वेबसाइट मोबाइल उपकरणों के लिए उपलब्ध नहीं है)
@@ -409,7 +406,7 @@
ग्रिड
ऑटो
त्रुटि दिखाएं
- सर्वर मल्टी थ्रेडेड डाउनलोड स्वीकार नहीं करता, पुनः कोशिश करे @string/msg_threads = 1 के साथ
+ सर्वर मल्टी थ्रेडेड डाउनलोड स्वीकार नहीं करता, @string/msg_threads = 1 के साथ पुनः कोशिश करें
\'स्टोरेज एक्सेस फ्रेमवर्क\' आपको बाहरी एसडी कार्ड पर डाउनलोड करने देता है
सेवा चुनें, वर्तमान चुनाव :
डिफ़ॉल्ट कियोस्क
@@ -505,7 +502,7 @@
अनगिनत विडीओज़
100+ विडीओज़
विवरण
- संबंधित स्ट्रीमस
+ संबंधित आइटम्स
टिप्पणियाँ
कृपया जांचें लें कि क्या आपके क्रैश पर चर्चा करने वाला मुद्दा पहले से मौजूद है। डुप्लिकेट टिकट बनाते समय, आप हमसे समय लेते हैं जो हम वास्तविक बग को ठीक करने के लिए खर्च कर सकते हैं।
गिटहब पर रिपोर्ट करें
@@ -658,7 +655,6 @@
मीडिया टनलिंग अक्षम करें
\"क्रैश द प्लेयर\" दिखाएं
लोड नहीं हुआ: %d
- %s इसका कारण प्रदान करता है:
टैग
लाइसेंस
यदि आपको ऐप का उपयोग करने में परेशानी हो रही है, तो सामान्य प्रश्नों के इन उत्तरों को देखना सुनिश्चित करें!
@@ -832,4 +828,26 @@
चैनल समूह पेज
पसंद
यूट्यूब अस्थायी प्लेलिस्ट के रूप में साझा करें
+ एंटरी मिटा दी गई
+ फाईल डिलीट करें
+ एंटरी मिटाऐं
+ %sहज़ार
+ पॉपअप प्लेयर इस्तेमाल करने के लिए, कृपया नीचे दिए गए Android सेटिंग्स मेनू में %1$s चुनें और %2$s चालू करें।
+ “अन्य ऐप्स पर डिस्प्ले की अनुमति दें”
+ %sमिलीअन
+ %sअरब
+ अकाउंट बंद कर दिया गया\n\n%1$s यह कारण बताता है: %2$s
+ साउंडक्लाउड टॉप 50 पेज हटा दिया गया
+ साउंडक्लाउड ने ओरिजिनल टॉप 50 चार्ट बंद कर दिए हैं। इससे जुड़ा टैब आपके मेन पेज से हटा दिया गया है।
+ YouTube कंबाइंड ट्रेंडिंग हटा दी गई
+ YouTube ने 21 जुलाई 2025 से कंबाइंड ट्रेंडिंग पेज बंद कर दिया है। NewPipe ने डिफ़ॉल्ट ट्रेंडिंग पेज को ट्रेंडिंग लाइवस्ट्रीम से बदल दिया है।\n\nआप \"सेटिंग्स > कंटेंट > मेन पेज कंटेंट\" में अलग-अलग ट्रेंडिंग पेज भी चुन सकते हैं।
+ गेमिंग ट्रेंडस
+ ट्रेंडिंग पॉडकास्ट
+ ट्रेंडिंग फिल्में और शो
+ ट्रेंडिंग संगीत
+ पले करते समय सर्वर से HTTP error 403 मिला, शायद स्ट्रीमिंग URL एक्सपायर होने या IP बैन की वजह से हुआ
+ पले करते समय सर्वर से HTTP error %1$s मिला
+ पले करते समय सर्वर से HTTP error 403 मिला, जो शायद IP बैन या स्ट्रीमिंग URL डीओबफस्केशन की दिक्कतों की वजह से हुआ है
+ %1$s ने डेटा देने से मना कर दिया, और यह कन्फर्म करने के लिए लॉगिन मांगा कि रिक्वेस्ट करने वाला बोट नहीं है।\n\nहो सकता है कि %1$s ने आपके IP को कुछ समय के लिए बैन कर दिया हो, आप कुछ समय इंतज़ार कर सकते हैं या किसी दूसरे IP पर स्विच कर सकते हैं (जैसे VPN ऑन/ऑफ करके, या WiFi से मोबाइल डेटा पर स्विच करके)।
+ यह कंटेंट अभी चुने गए देश के कंटेंट के लिए उपलब्ध नहीं है।\n\n\"सेटिंग्स > कंटेंट > डिफ़ॉल्ट कंटेंट देश\" से अपना चुनाव बदलें।
diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml
index c4cd60c0b..0eafb2930 100644
--- a/app/src/main/res/values-hr/strings.xml
+++ b/app/src/main/res/values-hr/strings.xml
@@ -2,7 +2,7 @@
Počni dodirom na povećalo.
Objavljeno %1$s
- Nije pronađen nijedan player streamova. Želiš li instalirati VLC\?
+ Nije pronađen nijedan player tokova. Želiš li instalirati VLC?
Instaliraj
Odustani
Otvori u pregledniku
@@ -97,9 +97,6 @@
Video
Audio
Pokušaj ponovo
- tis.
- mil
- mlrd.
Počni
Pauziraj
Izbriši
@@ -128,7 +125,7 @@
© %1$s od %2$s pod %3$s
O aplikaciji i ČPP
Licence
- Slobodan i mali streaming na Android uređaju.
+ Slobodan i mali tok na Android uređaju.
Pogledaj na GitHubu
NewPipe licenca
Ako imate ideja za prijevod, promjene u dizajnu, čišćenje koda ili neke veće promjene u kodu, pomoć je uvijek dobro došla. Što više radimo, to bolji postajemo!
@@ -163,7 +160,7 @@
- %s videa
Reproduciraj sve
- Nije bilo moguće reproducirati ovaj stream
+ Nije bilo moguće reproducirati ovaj tok
Dogodila se neoporavljiva greška playera
Oporavljanje od greške playera
Prikaži savjet za držanje
@@ -234,7 +231,7 @@
Poništava tvoju trenutačnu povijest, pretplate, playliste i (opcionalno) postavke
Izvezi povijest, pretplate, playliste i postavke
Izbriši povijest gledanja
- Briše povijest reproduciranih streamova i pozicije reprodukcije
+ Briše povijest reproduciranih tokova i pozicije reprodukcije
Izbrisati cijelu povijest gledanja\?
Povijest gledanja je izbrisana
Izbriši povijest pretraživanja
@@ -291,8 +288,8 @@
Bez ograničenja
Ograniči rezoluciju tijekom korištenja mobilnih podataka
Nijedan
- Nije pronađen nijedan player streamova (možeš instalirati VLC za reprodukciju).
- Preuzmi datoteku streama
+ Nije pronađen nijedan player tokova (možeš instalirati VLC za reprodukciju).
+ Preuzmi datoteku toka
Koristi brzo netočno premotavanje
Netočno premotavanje omogućuje playeru brže premotavanje uz manju točnost. Premotavanje od 5, 15 ili 25 sekundi s ovime ne radi
Otkaži pretplatu
@@ -312,8 +309,8 @@
Prikaži pogrešku
Izbriši sve podatke web-stranica iz predmemorije
Metapodaci su izbrisani
- Automatski dodaj sljedeći stream u popisa izvođenja
- Nastavi završavati (ne ponavljajući) popis reprodukcija dodavanjem povezanog streama
+ Automatski dodaj sljedeći tok u popisa izvođenja
+ Nastavi završavati (ne ponavljajući) popis reprodukcija dodavanjem povezanog toka
Zadana zemlja sadržaja
Otkrivanje grešaka
Obavijest o novoj verziji aplikacije
@@ -577,7 +574,7 @@
Obavijest šifriranja videa
Obavijesti o napretku šifriranja videa
Nedavni
- Isključi za skrivanje polja metapodataka s dodatnim podacima o autoru streama, sadržaju streama ili zahtjevu za pretraživanje
+ Isključi za skrivanje polja metapodataka s dodatnim podacima o autoru toka, sadržaju toka ili zahtjevu za pretraživanje
Prikaži metapodatke
Povezane stavke
Nijedna aplikacija na tvom uređaju ovo ne može otvoriti
@@ -642,14 +639,13 @@
Interno
Privatnost
Sada možeš odabrati tekst u opisu. Napomena: stranica će možda treperiti i možda nećeš moći kliknuti poveznice u načinu rada za odabir teksta.
- %s pruža ovaj razlog:
Obrada u tijeku … Može malo potrajati
Za ukljanjanje stavki povuci ih
Prikaži indikatore slike
- - Preuzimanje je gotovo
+ - %s preuzimanje je gotovo
- %s preuzimanja su gotova
- - %s preuzimanja su gotova
+ - %s preuzimanja je gotovo
Pokreni glavni player u cjeloekranskom prikazu
Dodaj u popis kao sljedeći
@@ -674,23 +670,23 @@
Došlo je do greške, pogledaj obavijest
Prekini rad playera
Obavijest playera
- Konfiguriraj obavijest trenutačno reproduciranog streama
+ Konfiguriraj obavijest trenutačno reproduciranog toka
Obavijesti
Novi videozapisi
- Obavijesti novih streamova od pretplaćenih kanala
+ Obavijesti novih tokova od pretplaćenih kanala
Želiš li izbrisati sve preuzete datoteke\?
Obavijesti su isljučene
Pretplatio/la si se na ovaj kanal
,
Uključi/isključi sve
Bilo kakva mreža
- Obavijesti novih streamova pretplaćenih kanala
+ Obavijesti novih tokova pretplaćenih kanala
Prikaži kratku poruku greške
- Učitavanje pojedinosti streama …
- Pokreni traženje novih streamova
+ Učitavanje pojedinosti toka …
+ Pokreni traženje novih tokova
Prvjeravanje učestalosti
Biblioteka „LeakCanary” nije dostupna
- Obavijesti o novim streamovima
+ Obavijesti o novim tokovima
Potrebna mrežna veza
Primaj obavijesti
Za ovu radnju nije pronađen odgovarajući upravljač datoteka.
@@ -702,12 +698,12 @@
Posto
Poluton
Streamovi koje aplikacija za preuzimanje još ne podržava se ne prikazuju
- Eksterni playeri ne podržavaju odabrani stream
+ Eksterni playeri ne podržavaju odabrani tok
Promijenite veličinu intervala učitavanja progresivnog sadržaja (trenutno %s). Niža vrijednost može ubrzati učitavanje
- - %s novi stream
- - %s nova streama
- - %s novih streamova
+ - %s novi tok
+ - %s nova toka
+ - %s novih tokova
Veličina intervala učitavanja reprodukcije
Nepoznat format
@@ -834,4 +830,36 @@
Uvijek koristi ExoPlayer postavku zaobilaženja videa za izlaznu površinu
Kartice za dohvaćanje prilikom aktualiziranja feeda. Ova opcija nema učinka ako se kanal aktualizira pomoću brzog modusa.
sekundarno
+ Pretraži %1$s
+ Pretraži %1$s (%2$s)
+ Popisi izvođenja
+ Da biste koristili Popup Player, odaberite %1$s u sljedećem izborniku postavki Androida i omogućite %2$s.
+ \"Dopusti prikaz preko drugih aplikacija\"
+ %sK
+ %sM
+ %sB
+ Izbriši datoteku
+ Obriši unos
+ Odaberite grupu feedova
+ Još nije stvorena nijedna grupa feedova
+ Stranica grupe kanala
+ Račun ukinut\n\n%1$s navodi ovaj razlog: %2$s
+ Ovo zaobilazno rješenje oslobađa i ponovno instancira video kodeke kada dođe do promjene površine, umjesto da se površina izravno postavlja na kodek. Već se koristi od strane ExoPlayera na nekim uređajima s ovim problemom, ova postavka ima učinak samo na Androidu 6 i novijim verzijama.\n\nOmogućavanje ove opcije može spriječiti pogreške reprodukcije prilikom prebacivanja trenutnog video playera ili prebacivanja na cijeli zaslon
+ Lajkovi
+ Podijeli kao privremenu playlistu na YouTubeu
+ Postavke u izvozu koji se uvozi koriste ranjivi format koji je zastario od verzije NewPipe 0.27.0. Provjerite je li izvoz koji se uvozi iz pouzdanog izvora i u budućnosti radije koristite samo izvoze dobivene iz NewPipe 0.27.0 ili novije verzije. Podrška za uvoz postavki u ovom ranjivom formatu uskoro će biti potpuno uklonjena, a zatim stare verzije NewPipea više neće moći uvoziti postavke izvoza iz novih verzija.
+ Stranica SoundCloud Top 50 uklonjena
+ SoundCloud je ukinuo originalne Top 50 ljestvice. Odgovarajuća kartica je uklonjena s vaše glavne stranice.
+ Uklonjeni kombinirani trendovi na YouTubeu
+ YouTube je ukinuo kombiniranu stranicu s trendovima od 21. srpnja 2025. NewPipe je zamijenio zadanu stranicu s trendovima s trendovima prijenosa uživo.\n\nTakođer možete odabrati različite stranice s trendovima u \"Postavke > Sadržaj > Sadržaj glavne stranice\".
+ Trendovi u igrama
+ Trendovi podcasti
+ Trendovi u filmovima i serijama
+ Glazba u trendu
+ Unos izbrisan
+ HTTP greška 403 primljena od poslužitelja tijekom reprodukcije, vjerojatno uzrokovana istekom URL-a za streaming ili zabranom IP adrese
+ HTTP greška %1$s primljena od poslužitelja tijekom reprodukcije
+ HTTP greška 403 primljena od poslužitelja tijekom reprodukcije, vjerojatno uzrokovana zabranom IP adrese ili problemima s deobfuskacijom URL-a za streaming
+ %1$s je odbio dati podatke, tražeći prijavu kako bi potvrdio da podnositelj zahtjeva nije bot.\n\nVašu IP adresu je možda privremeno zabranio %1$s, možete pričekati neko vrijeme ili se prebaciti na drugu IP adresu (na primjer uključivanjem/isključivanjem VPN-a ili prebacivanjem s WiFi-ja na mobilne podatke).
+ Ovaj sadržaj nije dostupan za trenutno odabranu zemlju sadržaja.\n\nPromijenite odabir u \"Postavke > Sadržaj > Zadana zemlja sadržaja\".
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index eb60e377f..12778fd32 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -49,7 +49,7 @@
Jelentés
Információ:
Ez történt:
- Saját hozzászólás (angolul):
+ Saját megjegyzés (angolul):
Részletek:
Elnézést, valami balul sült el.
Elnézést, ennek nem kellett volna megtörténnie.
@@ -90,7 +90,7 @@
Néhány felbontásnál eltávolítja a hangot
Feliratkozás
Feliratkozva
- További infó
+ További információ
Felugró ablak alapértelmezett felbontása
Magasabb felbontások megjelenítése
Csak bizonyos eszközök tudnak 2K/4K-s videókat lejátszani
@@ -166,9 +166,6 @@
Nincs letölthető adatfolyam
Nincs itt semmi pár tücskön kívül
Húzza az átrendezéshez
- e
- m
- M
Nincs feliratkozó
- %s feliratkozó
@@ -222,11 +219,11 @@
Legtöbbet lejátszott
Főoldal tartalma
Üres oldal
- Kioszk oldal
+ Témagyűjtemények
Csatornaoldal
Válasszon egy csatornát
Még nincs csatornafeliratkozás
- Válasszon egy kioszkot
+ Válasszon egy témagyűjteményt
Exportálva
Importálva
Nem érvényes ZIP-fájl
@@ -532,15 +529,14 @@
Fiók megnyitása
Csatorna részleteinek megjelenítése
Tartsa a sorba állításhoz
- Alapértelmezett kioszk
+ Alapértelmezett témagyűjtemény
A NewPipe egy copyleft szabad szoftver: tetszése szerint felhasználhatja, tanulmányozhatja, megoszthatja és fejlesztheti. Egész pontosan a Free Software Foundation által kiadott GNU General Public License 3-as, vagy (választható módon) újabb verziójának feltételei szerint módosíthatja vagy adhatja tovább.
Megoldás
Nyomja meg a „Kész” gombot, ha megoldotta
Ujjlenyomat számítása
Kapcsolódó elemek
- Ellenőrizze, hogy létezik-e már olyan jegy, amely az összeomlásával foglalkozik. Ha duplikált jegyet ad fel, akkor olyan időt vesz el tőlünk, amelyet a hiba javítására tudnánk fordítani.
+ Ellenőrizze, hogy létezik-e már hibajegy a leírt összeomlással kapcsolatban. Az ismétlődő hibajegyek létrehozása feleslegesen elvonja az erőforrásokat a hiba tényleges javításától.
Minimalizálás alkalmazásváltáskor
- A(z) %s ezt az okot adta meg:
Helyi keresési javaslatok
Távoli keresési javaslatok
A fő lejátszó teljes képernyős indítása
@@ -728,7 +724,7 @@
Eltávolítja az összes ismétlődő közvetítést ebből a lejátszólistáról\?
eredeti
Kezdőlap pozíciója
- A médiacsatornázás alapértelmezés szerint le van tiltva a saját eszközén, mivel a saját eszközmodellje nem támogatja azt.
+ A médiacsatornázás alapértelmezetten le van tiltva az eszközén, mivel a saját eszközmodellje nem támogatja azt.
Kezdőlapválasztó alulra helyezése
Nincs élő közvetítés
Nincs adatfolyam
@@ -805,4 +801,24 @@
Kedvelések
SoundCloud Top 50 oldal eltávolítva
A SoundCloud megszüntette az eredeti Top 50-es listákat. A megfelelő lap el lett távolítva a főoldalról.
+ YouTube „felkapott lapok” eltávolítva
+ A YouTube 2025. július 21-től megszüntette a „felkapott” oldalt. A NewPipe a korábbi alapértelmezett „felkapott” oldalt felkapott élő közvetítésekkel helyettesítette.\n\nA „Beállítások > Tartalom > Főoldal tartalma” menüpontban különböző felkapott lapokat is kiválaszthat.
+ Felkapott játékok
+ Felkapott podcastok
+ Felkapott filmek és sorozatok
+ Felkapott zenék
+ %se
+ %sm
+ %sM
+ A felugró ablakos lejátszó használatához válassza ki a(z) %1$s elemet a következő Android beállítások menüben, és engedélyezze a(z) %2$s elemet.
+ „Megjelenítés a többi alkalmazás fölött” engedélyezése
+ Fájl törlése
+ Bejegyzés törlése
+ Bejegyzés törölve
+ Fiók megszüntetve\n\n%1$s az alábbi ok miatt: %2$s
+ A lejátszás közben a kiszolgáló 403-as HTTP-hibát adott vissza, valószínűleg a közvetítési hivatkozás érvényessége lejárt vagy a IP-tiltás miatt
+ HTTP-hiba (%1$s) érkezett a kiszolgálótól a lejátszás során
+ HTTP 403-as hiba érkezett a kiszolgálótól a lejátszás közben, valószínűleg IP-tiltás vagy a közvetítési hivatkozás feloldási problémák miatt
+ %1$s visszautasította az adatok szolgáltatását, és bejelentkezést kér annak megerősítésére, hogy a kérés nem robot által érkezik.\n\nElőfordulhat, hogy az IP-címét ideiglenesen letiltotta %1$s, várhat egy keveset, vagy váltson egy másik IP-címre (például VPN be-/kikapcsolásával, vagy Wi-Fi-ről mobiladat-forgalomra váltva).
+ Ez a tartalom a jelenleg kiválasztott tartalom országában nem elérhető.\n\nVáltoztassa meg a „Beállítások > Tartalom >Tartalom alapértelmezett országa” menüpontban.
diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml
index b640a1232..bb9286dab 100644
--- a/app/src/main/res/values-in/strings.xml
+++ b/app/src/main/res/values-in/strings.xml
@@ -82,9 +82,6 @@
Meminta kode reCAPTCHA
Hitam
Semua
- r
- J
- T
Buka pada mode sembulan
Izin ini dibutuhkan untuk
\nmembuka di mode sembul
@@ -602,7 +599,6 @@
Aktifkan dapat memilih teks pada deskripsi
Anda sekarang dapat memilih teks di dalam deskripsi. Perhatikan bahwa halaman mungkin berkedip dan tautan tidak dapat diklik saat dalam mode pemilihan.
Buka situs web
- %s menyediakan alasan ini:
Akun dinonaktifkan
Mode langganan cepat tidak menyediakan lebih banyak info tentang ini.
Akun kreator telah dinonaktifkan.
@@ -820,4 +816,24 @@
Suka
Halaman Top 50 SoundCloud dihapus
SoundCloud telah menghentikan dukungan tangga lagu Top 50. Tab terkait telah dihapus dari halaman utama Anda.
+ Untuk menggunakan Pemutar Sembul, silakan pilih %1$s dalam menu pengaturan Android berikut dan aktifkan %2$s.
+ \"Izinkan menampilkan di atas aplikasi\"
+ Hapus berkas
+ Hapus entri
+ Akun dihapus\n\n%1$s menyediakan alasan ini: %2$s
+ Tren terpadu YouTube dihilangkan
+ YouTube telah mengakhiri halaman tren terpadu pada 21 Juli 2025. NewPipe mengganti halaman tren bawaan dengan tren siaran langsung.\n\nAnda juga dapat memilih halaman tren berbeda dalam \"Pengaturan > Konten > Konten di halaman utama\".
+ Tren permainan
+ Tren siniar
+ Tren film dan acara
+ Tren musik
+ Entri dihapus
+ Kesalahan HTTP 403 diterima dari server saat memutar, dapat disebabkan oleh URL streaming kedaluwarsa atau pemblokiran IP
+ Kesalahan HTTP %1$s diterima dari server saat memutar
+ Kesalahan HTTP 403 diterima dari server saat memutar, dapat disebabkan oleh pemblokiran IP atau masalah deobfuskasi URL streaming
+ %1$s menolak memberikan data, meminta login untuk memastikan peminta bukan bot.\n\nAlamat IP Anda mungkin telah diblokir sementara oleh %1$s, Anda dapat menunggu beberapa saat atau beralih ke alamat IP yang berbeda (misalnya dengan mengaktifkan/menonaktifkan VPN, atau beralih dari WiFi ke data seluler).
+ Konten ini tidak tersedia untuk negara konten yang saat ini dipilih.\n\nUbah pilihan Anda dari “Pengaturan > Konten > Negara konten bawaan”.
+ %sK
+ %sM
+ %sB
diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml
index bc85f0e06..387bce955 100644
--- a/app/src/main/res/values-is/strings.xml
+++ b/app/src/main/res/values-is/strings.xml
@@ -97,7 +97,6 @@
Hljóðstillingar
Spila í bakgrunni
Þegar hlekkur er opnaður — %s
- þús.
Líkar ekki við
Reyna aftur
Lýsing
@@ -217,7 +216,6 @@
Athugasemd þín (á ensku):
Engar niðurstöður
Myndskeið
- ma.
Engin áhorf
- %s áhorf
@@ -352,7 +350,6 @@
Flokkur
Merki
NewPipe er þróað af sjálfboðaliðum sem eyða frítíma sínum í að færa þér bestu notendaupplifunina. Gefðu til baka til að hjálpa forriturum að gera NewPipe enn betri á meðan þeir njóta kaffibolla.
- millj.
Slökktu á til að fela lýsingu og viðbótarupplýsingar myndskeiðs
Villa kom upp: %1$s
Þraut reCAPTCHA
@@ -576,7 +573,6 @@
Enginn viðeigandi skráarstjóri fannst fyrir þessa aðgerð.
\nVinsamlegast settu upp skráarstjóra sem styður Geymsluaðgangsramma (SAF)
Þetta efni er ekki fáanlegt í þínu landi.
- %s gefur þessa ástæðu:
Þetta efni er aðeins í boði fyrir notendur sem hafa greitt — það er ekki hægt að streyma því eða sækja með NewPipe.
Sjálfvirk (þema tækis)
Veldu uppáhalds næturþemu þína — %s
@@ -813,4 +809,16 @@
Líkar við
Topp 50 síða SoundCloud fjarlægð
SoundCloud er hætt með Topp 50 vinsældalistann. Viðkomandi flipi hefur verið fjarlægður af aðalsíðunni þinni.
+ %sK
+ %sM
+ %sB
+ Vinsælir leikir
+ Vinsæl hlaðvörp
+ Vinsælar kvikmyndir og þættir
+ Vinsæl tónlist
+ \"Leyfa birtingu ofan á öðrum forritum\"
+ Eyða skrá
+ Eyða færslu
+ Aðgangi lokað\n\n%1$s gefur þessa ástæðu: %2$s
+ Færslu eytt
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index d98875630..f73e7437a 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -82,9 +82,6 @@
Risoluzione reCAPTCHA
Nero
Tutto
- k
- M
- Mrd
È richiesta la risoluzione del reCAPTCHA
Apri in modalità popup
Riproduzione in modalità popup
@@ -622,7 +619,6 @@
Attiva la selezione del testo nella descrizione
È possibile selezionare il testo all\'interno della descrizione. In modalità selezione la pagina potrebbe sfarfallare e i collegamenti potrebbero non essere cliccabili.
Visita il sito
- %s fornisce questa motivazione:
Account chiuso
Il recupero veloce dei feed non fornisce ulteriori informazioni al riguardo.
L\'account dell\'autore è stato chiuso.
@@ -848,4 +844,24 @@
Mi piace
Pagina Top 50 di SoundCloud rimossa
SoundCloud ha dismesso i grafici Top 50 originali. La scheda relativa è stata rimossa dalla pagina principale.
+ %sK
+ %sMilio.
+ %sMilia.
+ Rimosse tendenze combinate YouTube
+ YouTube ha interrotto la pagina di tendenza combinata il 21 luglio 2025. NewPipe ha sostituito la pagina di tendenza predefinita con le dirette in tendenza.\n\nPuoi anche selezionare diverse pagine di tendenza in \"Impostazioni > Contenuto > Contenuto della pagina principale\".
+ Giochi in tendenza
+ Podcast in tendenza
+ Film e spettacoli in tendenza
+ Musica in tendenza
+ Per usare il riproduttore popup, seleziona %1$s nel seguente menu delle impostazioni Android e attiva %2$s.
+ “Consenti la visualizzazione sopra altre app”
+ Elimina file
+ Elimina voce
+ Account eliminato\n\n%1$s fornisce questa motivazione: %2$s
+ Voce eliminata
+ Errore HTTP 403 ricevuto dal server durante la riproduzione, probabilmente causato dalla scadenza dell\'URL in streaming o da un divieto dell\'IP
+ Errore HTTP %1$s ricevuto dal server durante la riproduzione
+ Errore HTTP 403 ricevuto dal server durante la riproduzione, probabilmente causato da un divieto dell\'IP o problemi di de-offuscamento dell\'URL in streaming
+ %1$s ha rifiutato di fornire i dati, chiedendo un accesso per confermare che il richiedente non sia un bot.\n\nIl tuo IP potrebbe essere stato temporaneamente vietato da %1$s, puoi aspettare un po\' di tempo o passare ad un IP diverso (ad esempio accendendo/spegnendo una VPN, o passando dal WiFi ai dati mobili).
+ Questo contenuto non è disponibile per il Paese dei contenuti attualmente selezionato.\n\nModifica la selezione da \"Impostazioni > Contenuti > Paese dei contenuti predefinito\".
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 25c1d9fe9..3274062b5 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -83,9 +83,6 @@
reCAPTCHA を要求しました
ブラック
すべて
- k
- M
- B
ポップアップモードで開く
ポップアップモードで開くには
\n権限の許可が必要です
@@ -615,7 +612,6 @@
オフ
オン
タブレットモード
- %s がこの理由を提示:
表示しない
低品質 (小)
高品質 (大)
diff --git a/app/src/main/res/values-ka/strings.xml b/app/src/main/res/values-ka/strings.xml
index 4fc00c0b3..819517ba4 100644
--- a/app/src/main/res/values-ka/strings.xml
+++ b/app/src/main/res/values-ka/strings.xml
@@ -237,9 +237,6 @@
ვიდეო
აუდიო
ხელახლა სცადეთ
- ათასი
- მლნ
- ბლნ
სერვისის გადართვა, ამჟამად არჩეულია:
გამოწერები არ არის
@@ -548,7 +545,6 @@
ეს ხელმიუწვდომელია თქვენი ქვეყნიდან.
ეს მასალა პირადულია, ამიტომაც NewPipe-ს მისი არც მთლიანად და არც თანდათანობით ჩამოწერა არ შეუძლია.
ანგარიში შეწყვეტილია
- %s იძლევა ამ მიზეზს:
ეს მასალა ხელმისაწვდომია მხოლოდ გადამხდელებისთვის, ამიტომაც NewPipe-ს მისი არც მთლიანად და არც თანდათანობით ჩამოწერა არ შეუძლია.
გამორჩეული
რადიო
@@ -741,4 +737,60 @@
არჩიე თავდაპირველი ხმის ჩანაწერი
ხმა: %s
ხმის ჩანაწერი
+ დიახ
+ არა
+ %1$s-ის ძიება
+ მოძებნეთ %1$s %2$s
+ დასაკრავი სიები
+ ქვემოთ მოცემული თითოეული შეტყობინების მოქმედების რედაქტირებისთვის მასზე შეხებით აირჩიეთ. პირველი სამი მოქმედება (დაკვრა/პაუზა, წინა და შემდეგი) სისტემის მიერ არის დაყენებული და მათი მორგება შეუძლებელია.
+ აღწერილობითი აუდიოს უპირატესობა
+ სარეზერვო ასლის შექმნა და აღდგენა
+ მთავარი ჩანართის ამომრჩევის ქვემოთ გადატანა
+ მთავარი ჩანართების პოზიცია
+ ამომხტარი ფანჯრის გამოსაყენებლად, გთხოვთ, აირჩიოთ %1$s შემდეგ Android პარამეტრების მენიუში და ჩართოთ %2$s.
+ “სხვა აპლიკაციებზე ჩვენების დაშვება“
+ %sათასი
+ %sმლნ
+ %sმლრდ
+ ნაკადები არ არის
+ პირდაპირი ტრანსლაციები არ არის
+ ფაილის წაშლა
+ ჩანაწერის წაშლა
+ აირჩიეთ არხის ჯგუფი
+ არხის ჯგუფი ჯერ არ შექმნილა
+ მედიის გვირაბირება თქვენს მოწყობილობაზე ნაგულისხმევად გამორთულია, რადგან თქვენი მოწყობილობის მოდელი, როგორც ცნობილია, მას არ უჭერს მხარს.
+ NewPipe-ს შეუძლია დროდადრო ავტომატურად შეამოწმოს ახალი ვერსიები და შეგატყობინოთ, როგორც კი ისინი ხელმისაწვდომი გახდება.\nგსურთ ამის ჩართვა?
+ პარამეტრების გადაყენება
+ ყველა პარამეტრის ნაგულისხმევ მნიშვნელობებზე დაბრუნება
+ ყველა პარამეტრის გადატვირთვა გააუქმებს თქვენს მიერ არჩეულ ყველა პარამეტრს და გადატვირთავს აპლიკაციას.\n\nდარწმუნებული ხართ, რომ გსურთ გაგრძელება?
+ მოწყობილობაზე საკმარისი თავისუფალი ადგილი არ არის
+ არხის ჯგუფის გვერდი
+ არხის ჩანართების მოძიება
+ არხის განახლებისას გამოსატანი ჩანართები. ამ პარამეტრს არანაირი ეფექტი არ აქვს, თუ არხი სწრაფი რეჟიმის გამოყენებით განახლდება.
+ ანგარიში შეწყვეტილია\n\n%1$s ამ მიზეზს იძლევა: %2$s
+ მინიატურები
+ ამტვირთავის ავატარები
+ ქვეარხის ავატარები
+ ავატარები
+ ბანერები
+ გამომწერები
+ ამ ნაკადში აუდიო ჩანაწერი უკვე უნდა იყოს წარმოდგენილი
+ გარე პლეერებისთვის აუდიო ჩანაწერის არჩევა
+ უცნობი
+ ExoPlayer-ის პარამეტრები
+ ExoPlayer-ის ზოგიერთი პარამეტრის მართვა. ამ ცვლილებების ძალაში შესასვლელად მოთამაშის გადატვირთვაა საჭირო.
+ გამოიყენეთ ExoPlayer-ის დეკოდერის სარეზერვო ფუნქცია
+ ჩართეთ ეს პარამეტრი, თუ დეკოდერის ინიციალიზაციის პრობლემები გაქვთ, რაც, თუ პირველადი დეკოდერების ინიციალიზაცია ვერ მოხერხდა, დაბალი პრიორიტეტის მქონე დეკოდერებს ეხება. ამან შეიძლება გამოიწვიოს დაკვრის დაბალი შესრულება, ვიდრე პირველადი დეკოდერების გამოყენებისას.
+ ყოველთვის გამოიყენეთ ExoPlayer-ის ვიდეო გამომავალი ზედაპირის პარამეტრების ალტერნატიული გადაწყვეტა
+ ეს გამოსავალი ათავისუფლებს და ხელახლა ააქტიურებს ვიდეო კოდეკებს ზედაპირის ცვლილებისას, ზედაპირის პირდაპირ კოდეკზე დაყენების ნაცვლად. ეს პარამეტრი უკვე გამოიყენება ExoPlayer-ის მიერ ზოგიერთ მოწყობილობაზე, რომელსაც ეს პრობლემა აქვს, და მოქმედებს მხოლოდ Android 6-ზე და უფრო მაღალ ვერსიებზე.\n\nამ პარამეტრის ჩართვამ შეიძლება თავიდან აიცილოს დაკვრის შეცდომები მიმდინარე ვიდეო პლეერის გადართვისას ან სრულ ეკრანზე გადართვისას.
+ თამაშების ტრენდები
+ ტრენდული პოდკასტები
+ ტრენდული ფილმები და შოუები
+ ტრენდული მუსიკა
+ ჩანაწერი წაშლილია
+ დაკვრის დროს სერვერიდან მიღებული HTTP შეცდომა 403, სავარაუდოდ, გამოწვეული სტრიმინგის URL-ის ვადის გასვლით ან IP აკრძალვით.
+ დაკვრის დროს სერვერიდან მიღებული HTTP შეცდომა %1$s
+ დაკვრის დროს სერვერიდან მიღებული HTTP შეცდომა 403, სავარაუდოდ, გამოწვეულია IP აკრძალვით ან სტრიმინგის URL-ის დებფუსკაციის პრობლემებით.
+ %1$s-მა უარი თქვა მონაცემების მიწოდებაზე და ითხოვა შესვლა იმის დასადასტურებლად, რომ მომთხოვნი რობოტი არ არის.\n\nშესაძლოა, თქვენი IP მისამართი დროებით აიკრძალა %1$s-ის მიერ, შეგიძლიათ დაელოდოთ ცოტა ხანს ან გადახვიდეთ სხვა IP მისამართზე (მაგალითად, VPN-ის ჩართვით/გამორთვით, ან WiFi-დან მობილურ მონაცემებზე გადართვით).
+ ეს კონტენტი ამჟამად არჩეული კონტენტის ქვეყნისთვის მიუწვდომელია.\n\nშეცვალეთ თქვენი არჩევანი „პარამეტრები > კონტენტი > ნაგულისხმევი კონტენტის ქვეყანა“-დან.
diff --git a/app/src/main/res/values-kab/strings.xml b/app/src/main/res/values-kab/strings.xml
index 97476fc46..29db74172 100644
--- a/app/src/main/res/values-kab/strings.xml
+++ b/app/src/main/res/values-kab/strings.xml
@@ -7,9 +7,9 @@
Sbedd asnas n Kore yexxuṣen\?
Sbedd
Asider
- Isidar
- Isidar
- Iɣewwaṛen
+ Isadaren
+ Isadaren
+ Iɣewwaren
Akter…
Tulya n telɣut…
Awurman
@@ -82,7 +82,6 @@
Sider
Asfaylu udhim
Ttu
- A
Kter
Ih
Amazray
@@ -128,7 +127,6 @@
Snifel isem
Asider ur yeddi ara
Tamwalit
- o
Aɣawas n deffir
Amazray
yesteɛfay
diff --git a/app/src/main/res/values-kmr/strings.xml b/app/src/main/res/values-kmr/strings.xml
index b5e5235d5..24bc5574e 100644
--- a/app/src/main/res/values-kmr/strings.xml
+++ b/app/src/main/res/values-kmr/strings.xml
@@ -49,9 +49,6 @@
Ne abone
Karûbarê veguheztinê, niha hatî hilbijartin:
- B
- M
- k
Dîsa biceribîne
Deng
Vîdyo
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index cfc328a20..39f854d35 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -24,7 +24,7 @@
다운로드
다음/유사한 비디오 표시
지원하지 않는 URL입니다
- 기본 컨텐츠 언어
+ 기본 콘텐츠 언어
비디오 및 오디오
비디오 재생, 구간:
업로더 썸네일
@@ -42,13 +42,13 @@
백그라운드에서 재생 중
네트워크 오류
돋보기를 탭하여 시작합니다.
- 컨텐츠
- 연령 제한 컨텐츠 보여주기
+ 콘텐츠
+ 연령 제한 콘텐츠 보여주기
라이브
오류
모든 썸네일을 불러올 수 없습니다
웹사이트를 가져올 수 없습니다
- 컨텐츠를 사용할 수 없습니다
+ 콘텐츠를 사용할 수 없습니다
다운로드 메뉴를 설정할 수 없습니다
죄송합니다. 오류가 발생했습니다.
이메일을 통해 보고
@@ -116,9 +116,6 @@
무엇:\\n요청:\\n콘텐츠 언어:\\n콘텐츠 국가:\\n앱 언어:\\n서비스:\\nGMT 시간:\\n패키지:\\n버전:\\nOS 버전:
결과 없음
구독할 항목을 추가하세요
- 천
- 백만
- 십억
구독자 없음
- 구독자 %s명
@@ -287,7 +284,7 @@
영상과 소리 분리 (왜곡이 발생할 수 있음)
다운로드 가능한 스트림이 없습니다
선호하는 열기 동작
- 컨텐츠를 열 때 사용할 기본 동작 — %s
+ 콘텐츠를 열 때 사용할 기본 동작 — %s
자막
플레이어 자막 글자 크기와 배경 스타일을 수정합니다. 적용하려면 앱을 다시 시작해야 합니다
채널
@@ -648,7 +645,6 @@
챕터
최근
계정이 해지됨
- %s은(는) 다음과 같은 이유를 제공:
이것은 적어도 귀하의 국가에서 SoundCloud Go+ 트랙이므로 NewPipe에서 스트리밍하거나 다운로드할 수 없습니다.
자동 (장치 테마)
고정된 댓글
@@ -809,4 +805,25 @@
네
설정 초기화
모든 설정을 기본값으로 초기화
+ YouTube 임시 재생목록으로 공유
+ SoundCloud Top 50 페이지가 삭제되었습니다
+ SoundCloud에서 더 이상 기존 Top 50 차트를 제공하지 않습니다. 해당하는 탭이 메인 페이지에서 제거되었습니다.
+ %s천
+ %s백만
+ %s십억
+ 파일 삭제
+ 피드 그룹 선택
+ 피드 그룹을 생성하지 않았습니다
+ 채널 그룹 페이지
+ 계정 정지됨\n\n%1$s에서 제공한 이유: %2$s
+ 재생목록
+ %1$s 검색
+ %1$s 검색 (%2$s)
+ \"다른 앱 위에 표시 허용\"
+ YouTube 통합 인기 급상승 동영상이 삭제되었습니다
+ YouTube에서 2025년 7월 21일부로 더 이상 통합 인기 급상승 동영상을 제공하지 않습니다. NewPipe에서는 기본 인기 급상승 페이지를 인기 급상승 실시간 페이지로 교체했습니다.\n\n\"설정 > 콘텐츠 > 메인 화면의 내용\"에서 다른 인기 급상승 페이지를 선택할 수 있습니다.
+ 인기 급상승 게임
+ 인기 급상승 팟캐스트
+ 인기 급상승 영화 및 쇼
+ 인기 급상승 음악
diff --git a/app/src/main/res/values-ku/strings.xml b/app/src/main/res/values-ku/strings.xml
index 2f3934fff..3dc51fcc8 100644
--- a/app/src/main/res/values-ku/strings.xml
+++ b/app/src/main/res/values-ku/strings.xml
@@ -133,9 +133,6 @@
ڤیدیۆ
دەنگ
هەوڵدانەوە
- هەزار
- ملیۆن
- بلیۆن
هیچ بەشداربوویەک نییە
- %s بەشداربوو
diff --git a/app/src/main/res/values-lmo/strings.xml b/app/src/main/res/values-lmo/strings.xml
new file mode 100644
index 000000000..80f3dd9c6
--- /dev/null
+++ b/app/src/main/res/values-lmo/strings.xml
@@ -0,0 +1,5 @@
+
+
+ Pigia la lente per inziaa.
+ Canai
+
diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml
index feb11a01c..20419fef6 100644
--- a/app/src/main/res/values-lt/strings.xml
+++ b/app/src/main/res/values-lt/strings.xml
@@ -139,9 +139,6 @@
Atstatoma po grotuvo klaidos
Nėra rezultatų
Čia nieko nėra išskyrus svirplius
- Tūkst.
- Mln.
- Mlrd.
Nėra prenumeratorių
Nėra peržiūrų
@@ -626,7 +623,6 @@
Įgalinti teksto pasirinkimą apraše
Neleisti pasirinkti teksto apraše
Dabar apraše galite pasirinkti tekstą aprašyme. Atminkite, kad puslapis gali mirgėti, o nuorodos gali būti nespustelėjamos, kai veikia pasirinkimo režimas.
- %s pateikia šią priežastį:
Paskyra anuliuota
Greito srauto režimas nesuteikia daugiau informacijos apie tai.
Autoriaus paskyra anuliuota.
@@ -840,4 +836,26 @@
Grojaraščiai
Antrinis
Dalintis kaip laikinuoju youtube grojaraščiu
+ Ieškoti %1$s
+ Ieškoti %1$s (%2$s)
+ Norėdami įjungti \"Popup Grotuvą\" pasirinkite Android nustatymų meniu pasirinkite %1$s ir įjunkite %2$s.
+ \"Leisti piešti virš kitų langų\"
+ %sK
+ %sM
+ %sB
+ Pašalinti failą
+ Ištrinti įrašą
+ Pasirinkite kanalo grupę
+ Dar nėra kanalo grupės
+ Kanalo grupės puslapis
+ Paskyra pašalinta\n\n%1$s dėl šios priežasties: %2$s
+ Mėgsta
+ SoundCloud Top 50 puslapis pašalintas
+ SoundCloud nebeteikia Top 50. Šis puslapis pašalintas iš jūsų pagrindinio puslapio.
+ YouTube sujungti rekomenduojami pašalinti
+ Žaidimų pasiūlymai
+ Mėgstami podcasts
+ Mėgstami filmai ir laidos
+ Mėgstama muzika
+ Įrašas pašalintas
diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml
index 2d1c60256..0eb6e4201 100644
--- a/app/src/main/res/values-lv/strings.xml
+++ b/app/src/main/res/values-lv/strings.xml
@@ -136,9 +136,6 @@
Nav abonamentu
Izvēlaties pakalpojumu, šobrīd izvēlēts:
- B
- M
- k
Atkārtot
Audio
Video
@@ -530,7 +527,7 @@
Netika atrasts video atskaņotājs. Uzstādīt VLC?
Publicēts %1$s
Nospiediet uz meklēšanas ikonas, lai sāktu.
- Iekrāsot paziņojumu
+ Pielāgot paziņojumu krāsu
Nekas
Ielādējas
Sajaukt
@@ -634,7 +631,6 @@
\nNewPipe turpmāk nevarēs ielādēt šo plūsmu.
\nVai vēlaties atteikties no šī kanāla abonēšanas\?
Ātrās straumes režīms nesniedz vairāk informācijas par šo.
- %s dod šādu pamatojumu:
Izslēgt teksta atlasīšanu video aprakstā
Iekšeji
Autors piekrīt
diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml
index ff3f9b687..3a8fa2f07 100644
--- a/app/src/main/res/values-mk/strings.xml
+++ b/app/src/main/res/values-mk/strings.xml
@@ -146,9 +146,6 @@
Видео
Звук
Пробај повторно
- илјади
- M
- милијарди
Нема зачленети
- %s зачленет
@@ -434,7 +431,6 @@
Неуспешно вчитување на новинска лента за „%s“.
Прикажи / скриј стримови
Оваа содржина е приватна, така што не може да биде емитувана или преземена од страна на NewPipe.
- %s ја посочува следната причина:
Истакнато
Радио
Автоматски (режим на уредот)
diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml
index 39ce5e57f..5a449025e 100644
--- a/app/src/main/res/values-ml/strings.xml
+++ b/app/src/main/res/values-ml/strings.xml
@@ -183,9 +183,6 @@
സബ്ക്രൈബേഴ്സ് ഇല്ല
സേവനം മാറ്റുക, ഇപ്പോൾ തിരഞ്ഞെടുത്തത്:
- B
- k
- M
വീണ്ടും ശ്രമിക്കുക
ഓഡിയോ
വീഡിയോ
@@ -616,7 +613,6 @@
ടാഗുക്കൾ
വിഭാഗം
താക്കൾക് ഇപ്പോൾ ഡിസ്ക്രിപ്ഷൻ ബോക്സിലെ ടെക്സ്റ്റ് തിരഞ്ഞെടുക്കാൻ സാധിക്കും. ശ്രെദ്ധിക്കുക സെലെക്ഷൻ മോഡിൽ പേജ് ചിലപ്പോൾ മിന്നുകയും ലിങ്കുകൾ ക്ലിക്ക് ചെയ്യാനാകാതെയും വന്നേക്കാം.
- ഇതിന്റെ കാരണം %s നൽകും:
അക്കൗണ്ട് ഇല്ലാതായിരിക്കുന്നു
ഫാസ്റ്റ് ഫീഡ് മോഡ് കൂടുതൽ വിവരങ്ങൾ നൽകില്ല.
സൃഷ്ടാവിന്റെ അക്കൗണ്ട് ഇല്ലാതായിരിക്കുന്നു.
diff --git a/app/src/main/res/values-mr/strings.xml b/app/src/main/res/values-mr/strings.xml
index 304858d84..7a6b2eda4 100644
--- a/app/src/main/res/values-mr/strings.xml
+++ b/app/src/main/res/values-mr/strings.xml
@@ -138,11 +138,8 @@
डेबग
अपडेट
थेट
- ब
प्लेलिस्ट
- म
फाईल
- के
परवाना
चेकसम
इतिहास
diff --git a/app/src/main/res/values-ms/strings.xml b/app/src/main/res/values-ms/strings.xml
index bb0527655..e70e61a74 100644
--- a/app/src/main/res/values-ms/strings.xml
+++ b/app/src/main/res/values-ms/strings.xml
@@ -171,9 +171,6 @@
Video
Audio
Cuba semula
- K
- J
- B
Tiada pelanggan
- %s pelanggan
diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml
index c2311585a..d5edc2060 100644
--- a/app/src/main/res/values-nb-rNO/strings.xml
+++ b/app/src/main/res/values-nb-rNO/strings.xml
@@ -89,9 +89,6 @@
Spiller av i oppsprettsmodus
Alle
Avskrudd
- k
- M
- Mrd.
Denne tilgangen trengs for
\nåpning i oppsprettsmodus
reCAPTCHA-oppgave forespurt
@@ -603,7 +600,6 @@
\nØnsker du å oppheve ditt abonnement på denne kanalen\?
Skru av merking av tekst i beskrivelsen
Skru på merking av tekst i beskrivelsen
- %s oppgav denne grunnen:
Konto terminert
Kunne ikke laste inn informasjonskanal for «%s».
Kunne ikke laste inn informasjonskanal
diff --git a/app/src/main/res/values-ne/strings.xml b/app/src/main/res/values-ne/strings.xml
index dd570b82e..b40145aa6 100644
--- a/app/src/main/res/values-ne/strings.xml
+++ b/app/src/main/res/values-ne/strings.xml
@@ -176,9 +176,6 @@
भिडियो
अडियो
पुन: प्रयास
- हजार
- करोड
- अर्ब
कुनै सदस्यहरू छैनन्
- %s सदस्य
diff --git a/app/src/main/res/values-nl-rBE/strings.xml b/app/src/main/res/values-nl-rBE/strings.xml
index a78b96585..02d772023 100644
--- a/app/src/main/res/values-nl-rBE/strings.xml
+++ b/app/src/main/res/values-nl-rBE/strings.xml
@@ -147,9 +147,6 @@
Video
Geluid
Opnieuw proberen
- k
- M
- mld.
Geen abonnees
- %s abonnee
@@ -638,4 +635,6 @@
Verkies beschrijvende audio
Verkies originele audio
Selecteer het oorspronkelijke audiospoor, ongeacht de taal
+ Zoeken%1$s
+ Zoeken%1$s(%2$s)
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 0c16a5c9b..4c8a28745 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -84,9 +84,6 @@
reCAPTCHA-uitdaging gevraagd
Openen in pop-upmodus
Alles
- dznd.
- mln.
- mld.
Deze machtiging is vereist om te
\nopenen in pop-upmodus
Speelt af in pop-upmodus
@@ -615,7 +612,6 @@
Aan
Tablet-modus
Website openen
- %s geeft de volgende reden:
Account getermineerd
De snelle feed mode levert hierover niet meer informatie.
De account van de auteur is getermineerd.
@@ -829,4 +825,29 @@
Selecteer een feedgroep
Kanaalgroeppagina
Nog geen feedgroep geselecteerd
+ Zoeken met %1$s
+ Zoeken met %1$s (%2$s)
+ Vind-ik-leuks
+ Trending podcasts
+ Trending games
+ Trending films en series
+ Trending muziek
+ ‘SoundCloud Top 50’-pagina verwijderd
+ SoundCloud heeft de originele Top 50-hitlijsten stopgezet. Het bijbehorende tabblad is van uw hoofdpagina verwijderd.
+ YouTube gecombineerde trending verwijderd
+ YouTube heeft de gecombineerde trendingpagina per 21 juli 2025 stopgezet. NewPipe heeft de standaardtrendingpagina vervangen door de trending livestreams.\n\nU kunt ook andere trendingpagina\'s selecteren via \'Instellingen > Inhoud > Inhoud van de hoofdpagina\'.
+ %s dznd.
+ %s mln.
+ %s mld.
+ Bestand verwijderen
+ Item verwijderen
+ Item verwijderd
+ Om de Pop-up-speler te gebruiken, selecteert u %1$s in het volgende Android-instellingenmenu en schakelt u %2$s in.
+ ‘Weergeven vóór andere apps toestaan’
+ Account beëindigd\n\n%1$s geeft de volgende reden: %2$s
+ HTTP-fout 403 ontvangen van de server tijdens het afspelen, waarschijnlijk veroorzaakt door het verlopen van de streaming-url of een ip-blokkade
+ HTTP-fout %1$s ontvangen van de server tijdens het afspelen
+ HTTP-fout 403 ontvangen van de server tijdens het afspelen, waarschijnlijk veroorzaakt door een ip-blokkade of problemen met de deobfuscatie van de streaming-url
+ %1$s weigerde gegevens te verstrekken en vroeg om een login om te bevestigen dat de aanvrager geen bot is.\n\nUw ip-adres is mogelijk tijdelijk geblokkeerd door %1$s. U kunt even wachten of overschakelen naar een ander ip-adres (bijvoorbeeld door een vpn in of uit te schakelen, of door over te schakelen van wifi naar mobiele data).
+ Deze inhoud is niet beschikbaar voor het momenteel geselecteerde inhoudsland.\n\nWijzig uw selectie via ‘Instellingen > Inhoud > Standaardland voor inhoud’.
diff --git a/app/src/main/res/values-nqo/strings.xml b/app/src/main/res/values-nqo/strings.xml
index 016ce1ba2..caf8509e3 100644
--- a/app/src/main/res/values-nqo/strings.xml
+++ b/app/src/main/res/values-nqo/strings.xml
@@ -178,9 +178,6 @@
ߞߐߝߟߌ߫ ߕߍ߫ ߦߋ߲߬
ߡߍ߲ߕߊ
ߞߵߊ߬ ߡߊߛߊ߬ߦߌ߬
- ߥߊ߯
- ߞߋ߲߬
- ߥߟߡ
ߞߊ߬ ߥߏ߬ߦߏ߫ ߣߊ߬ߕߊ ߝߙߊ߬ ߕߎ߲߰ߠߌ߲ ߠߊ߫ ߞߍ߲ߖߘߍߡߊߓߟߏ ߡߊ߬
ߞߊ߬ ߕߎ߲߰ߠߌ߲ ߘߐߞߊ߬ߙߊ߲ ߓߟߏߕߎ߰ (ߞߊߣߊ߬ ߡߊߛߊ߬ߦߌ߬) ߥߏ߬ߦߏ߫ ߢߐ߲߰ߘߐ ߟߎ߫ ߟߊ߫
ߕߏߟߏ߲ߟߊ߲߫ ߥߊ߲߬ߥߊ߲ ߣߎߡߊ߲߫ ߕߟߊ ߖߍ߰ߙߍ ߛߎߥߊ߲ߘߌ߫
@@ -630,7 +627,6 @@
ߞߐߕߐ߯ ߡߊߡߙߊߟߊ߲߫ ߛߌ߫ ߡߊ߫ ߛߐ߬ߘߐ߲߬ ߞߋߥߊߟߌ ߣߌ߲߬ ߞߊ߲ߡߊ߬.
\nߘߌ߬ߢߍ߬ ߦߋ߫ ߞߐߕߐ߯ ߡߊߡߙߊߟߊ߲ ߘߏ߫ ߡߊߞߍ߫ ߡߍ߲ ߣߌ߫ ߡߙߊ߬ߘߐ߬ߦߊ ߟߊߛߐ߬ߘߐ߲ ߡߎ߬ߙߊ߲߬ߞߊ߲ߞߋ ߘߌ߫ ߓߍ߲߬
ߦߋߡߍ߲ߕߊ ߘߌ߫ ߡߊߛߐ߬ߘߐ߲߬ YouTube Music Premium ߛߌ߲߬ߝߏ߲ ߠߎ߬ ߟߋ߬ ߘߐߙߐ߲߫ ߓߟߏ߫߸ ߏ߬ ߘߐ߫ ߊ߬ ߕߍ߫ ߛߋ߫ ߘߐߛߊߙߌ߫ ߟߊ߫ ߥߟߊ߫ ߞߵߊ߬ ߟߊߖߌ߰ ߣߌߎߔߌߔ ߓߟߏ.
- %s ߦߋ߫ ߞߎ߲߭ ߣߌ߲߬ ߠߋ߬ ߝߐ߫ ߟߊ߫:
ߛߊ߲ߞߊߥߟߌ
ߥߎߢߊ߲ߓߍ߲
ߖߘߍ߬ߢߍ߫ (ߕߙߏߞߏ߫ ߛߊߛߊ)
diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml
index cf9ebdb97..81184d526 100644
--- a/app/src/main/res/values-or/strings.xml
+++ b/app/src/main/res/values-or/strings.xml
@@ -438,7 +438,6 @@
ନାପସନ୍ଦ
ମନ୍ତବ୍ୟ ଗୁଡିକ
ବର୍ଣ୍ଣନା
- ନିୟୁତ
ସମାଧାନ
ପ୍ଲେବେକ୍ ସ୍ପିଡ୍ ନିୟନ୍ତ୍ରଣ
ଟେମ୍ପୋ
@@ -487,7 +486,6 @@
ସଦସ୍ୟତା ଚୟନ କରନ୍ତୁ
କୌଣସି ସଦସ୍ୟତା ଚୟନ ହୋଇନାହିଁ
ଦ୍ରୁତ ମୋଡ୍ ସକ୍ଷମ କରନ୍ତୁ
- %s ଏହି କାରଣ ପ୍ରଦାନ କରେ:
ଚ୍ୟାନେଲର ଅବତାର ଥମ୍ୱନେଲ୍
ବୈଶିଷ୍ଟ୍ୟ
ରେଡିଓ
@@ -528,7 +526,6 @@
ସମ୍ବନ୍ଧୀୟ ଆଇଟମ୍ ଗୁଡ଼ିକ
ପୁନଃ ସଯାଇବାକୁ ଡ୍ରାଗ୍ କରନ୍ତୁ
ବିରାମ
- ଵୃନ୍ଦ
କୌଣସି ଗ୍ରାହକ ନାହାଁନ୍ତି
ସୃଷ୍ଟି କରନ୍ତୁ
ବିବରଣୀ ପାଇଁ ଟ୍ୟାପ୍ କରନ୍ତୁ
@@ -609,7 +606,6 @@
ବହିଃ-ଚାଳକ ପାଇଁ ଗୁଣବତ୍ତା ଚୟନ କରନ୍ତୁ
ପିନ୍ ହୋଇଥିବା ମନ୍ତବ୍ୟ
ୱେବସାଇଟ୍ ଖୋଲନ୍ତୁ
- ହଜାର
ସୂଚନା ପାଇବା…
- %s ଗ୍ରାହକ
diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml
index 757632994..9dfc8143e 100644
--- a/app/src/main/res/values-pa/strings.xml
+++ b/app/src/main/res/values-pa/strings.xml
@@ -29,7 +29,7 @@
ਨਵਾਂ ਕੀ ਹੈ
ਬੈਕਗ੍ਰਾਊਂਡ
ਪੌਪ-ਅਪ
- ਵਿੱਚ ਸ਼ਾਮਿਲ ਕਰੋ
+ ਦੇ ਵਿੱਚ ਜੋੜ੍ਹੋ
ਵੀਡੀਓ ਲਈ ਡਾਊਨਲੋਡ ਫ਼ੋਲਡਰ
ਡਾਊਨਲੋਡ ਕੀਤੀਆਂ ਵੀਡੀਓ ਫ਼ਾਈਲਾਂ ਇੱਥੇ ਜਮ੍ਹਾਂ ਹੁੰਦੀਆਂ ਹਨ
ਵੀਡੀਓ ਫ਼ਾਈਲਾਂ ਲਈ ਡਾਊਨਲੋਡ ਫ਼ੋਲਡਰ ਚੁਣੋ
@@ -93,7 +93,7 @@
ਬੰਦ ਕੀਤਾ
ਸਾਫ ਕਰੋ
ਵਧੀਆ ਰੈਜ਼ੋਲਿਊਸ਼ਨ
- ਵਾਪਿਸ
+ ਅਣ-ਕੀਤਾ ਕਰੋ
ਸਾਰੇ ਚਲਾਓ
ਹਮੇਸ਼ਾਂ
ਸਿਰਫ਼ ਇਸ ਬਾਰ
@@ -153,9 +153,6 @@
ਵੀਡੀਓ
ਆਡੀਓ
ਦੋਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ
- ਹਜ਼ਾਰ
- ਮਿਲੀਅਨ
- ਅਰਬ
ਕੋਈ ਸਬਸਕ੍ਰਾਈਬਰ ਨਹੀਂ
- %s ਸਬਸਕ੍ਰਾਈਬਰ
@@ -187,8 +184,7 @@
ਕ੍ਰਿਪਾ ਕਰਕੇ ਉਡੀਕ ਕਰੋ…
ਕਲਿਪ-ਬੋਰਡ ਵਿੱਚ ਕਾਪੀ ਹੋ ਗਿਆ ਹੈ
ਬਾਅਦ ਵਿੱਚ ਸੈਟਿੰਗਾਂ ਵਿਚੋਂ ਇੱਕ ਡਾਊਨਲੋਡ ਫੋਲਡਰ ਨੂੰ ਚੁਣੋ
- ਪੌਪ-ਅਪ ਮੋਡ ਵਿੱਚ ਖੋਲ੍ਹਣ ਵਾਸਤੇ
-\nਇਸ ਇਜਾਜ਼ਤ ਦੀ ਲੋੜ ਹੈ
+ ਪੌਪ-ਅਪ ਮੋਡ ਵਿੱਚ ਖੋਲ੍ਹਣ ਵਾਸਤੇ\nਇਸ ਇਜਾਜ਼ਤ ਦੀ ਲੋੜ ਹੈ
1 ਆਈਟਮ ਮਿਟਾਈ ਗਈ।
ReCaptcha ਚੁਣੌਤੀ
ReCaptcha ਚੁਣੌਤੀ ਲਈ ਬੇਨਤੀ
@@ -281,36 +277,19 @@
ਪਿੱਛਲਾ ਐਕਸਪੋਰਟ
ਸਬਸਕ੍ਰਿਪਸ਼ਨਾਂ ਇੰਪੋਰਟ ਨਹੀਂ ਹੋ ਸਕੀਆਂ
ਸਬਸਕ੍ਰਿਪਸ਼ਨਾਂ ਐਕਸਪੋਰਟ ਨਹੀਂ ਹੋ ਸਕੀਆਂ
- ਗੂਗਲ ਟੇਕਅਊਟ ਤੋਂ ਯੂਟਿਊਬ ਸਬਸਕ੍ਰਿਪਸ਼ਨਾਂ ਇੰਪੋਰਟ ਕਰਨ ਲਈ ਐਕਸਪੋਰਟ ਫਾਈਲ ਡਾਊਨਲੋਡ ਕਰੋ:
-\n
-\n1. ਇਸ URL ਤੇ ਜਾਓ: %1$s
-\n2. ਮੰਗਣ ਤੇ ਆਪਣੇ ਖਾਤੇ \'ਚ ਲਾਗ-ਇਨ ਕਰੋ
-\n3. ਕਲਿੱਕ ਕਰੋ \" All data incuded\" ਤੇ, ਫੇਰ \"Deselect all\" ਤੇ ਫੇਰ ਸਿਰਫ \"subscriprion\" ਚੁਣੋ ਅਤੇ \"OK\" ਕਰੋ
-\n4. \"Next step\" ਤੇ ਕਲਿੱਕ ਕਰੋ ਤੇ ਫੇਰ \"create export\" ਤੇ
-\n5. ਡਾਊਨਲੋਡ ਬਟਨ ਦਿਖਾਈ ਦੇਣ ਤੇ ਇਸ ਤੇ ਕਲਿੱਕ ਕਰੋ।ਇੱਕ ਡਾਉਨਲੋਡ ਸ਼ੁਰੂ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ (ਇਹੀ ਐਕਸਪੋਰਟ ਫਾਈਲ ਹੈ)
-\n6. ਥੱਲੇ ਇੰਪੋਰਟ ਫਾਈਲ ਤੇ ਕਲਿੱਕ ਕਰੋ ਤੇ ਡਾਊਨਲੋਡ ਕੀਤੀ .zip ਫਾਈਲ ਚੁਣੋ
-\n7. [ਜੇ .zip ਤੋਂ ਐਕਸਪੋਰਟ ਫੇਲ ਹੋ ਜਾਂਦੀ ਹੈ] ਤਾਂ .csv ਫਾਈਲ ਐਕਸਟਰੈਕਟ ਕਰੋ (ਆਮ ਤੌਰ ਤੇ \"YouTube and YouTube Music/subscriptions/subscriptions.csv\"), ਥੱਲੇ ਦਿੱਤੇ ਇੰਪੋਰਟ ਫਾਈਲ ਤੇ ਕਲਿੱਕ ਕਰਕੇ ਐਕਸਟਰੈਕਟ ਕੀਤੀ csv ਫਾਈਲ ਚੁਣੋ
- URL ਜਾਂ ਆਪਣੀ ID ਟਾਈਪ ਕਰਕੇ ਸਾਉੰਡ ਕਲਾਉਡ ਪ੍ਰੋਫਾਈਲ ਇੰਪੋਰਟ ਕਰੋ:
-\n
-\n1. ਇੱਕ ਵੈਬ-ਬ੍ਰਾਊਜ਼ਰ ਵਿੱਚ \"ਡੈਸਕਟਾਪ ਮੋਡ\" ਨੂੰ ਚਾਲੂ ਕਰੋ (ਸਾਈਟ ਮੋਬਾਈਲ ਉਪਕਰਣਾਂ ਲਈ ਉਪਲਬਧ ਨਹੀਂ ਹੈ)
-\n2. ਇਸ URL ਤੇ ਜਾਓ: %1$s
-\n3. ਆਪਣੇ ਖਾਤੇ ਚ ਲੌਗ-ਇਨ ਕਰੋ
-\n4. ਨਿਰਦੇਸ਼ਤ ਕੀਤੇ ਗਏ ਪ੍ਰੋਫਾਈਲ URL ਨੂੰ ਕਾਪੀ ਕਰੋ.
+ ਗੂਗਲ ਟੇਕਆਊਟ ਤੋਂ ਯੂਟਿਊਬ ਸਬਸਕ੍ਰਿਪਸ਼ਨਾਂ ਇੰਪੋਰਟ ਕਰਨ ਲਈ ਐਕਸਪੋਰਟ ਫਾਈਲ ਡਾਊਨਲੋਡ ਕਰੋ:\n\n1. ਇਸ URL ਤੇ ਜਾਓ: %1$s\n2. ਮੰਗਣ ਤੇ ਆਪਣੇ ਖਾਤੇ \'ਚ ਲਾਗ-ਇਨ ਕਰੋ\n3. ਕਲਿੱਕ ਕਰੋ \" All data incuded\" ਤੇ, ਫੇਰ \"Deselect all\" ਤੇ ਫੇਰ ਸਿਰਫ \"subscriprion\" ਚੁਣੋ ਅਤੇ \"OK\" ਕਰੋ\n4. \"Next step\" ਤੇ ਕਲਿੱਕ ਕਰੋ ਅਤੇ ਫੇਰ \"create export\" ਤੇ\n5. ਡਾਊਨਲੋਡ ਬਟਨ ਦਿਖਾਈ ਦੇਣ ਤੇ ਇਸ ਤੇ ਕਲਿੱਕ ਕਰੋ। ਇੱਕ ਡਾਉਨਲੋਡ ਸ਼ੁਰੂ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ (ਇਹੀ ਐਕਸਪੋਰਟ ਫਾਈਲ ਹੈ)\n6. ਥੱਲੇ ਇੰਪੋਰਟ ਫਾਈਲ ਤੇ ਕਲਿੱਕ ਕਰੋ ਤੇ ਡਾਊਨਲੋਡ ਕੀਤੀ .zip ਫਾਈਲ ਚੁਣੋ\n7. [ਜੇ .zip ਤੋਂ ਐਕਸਪੋਰਟ ਫੇਲ ਹੋ ਜਾਂਦੀ ਹੈ] ਤਾਂ .csv ਫਾਈਲ ਐਕਸਟਰੈਕਟ ਕਰੋ (ਆਮ ਤੌਰ ਤੇ \"YouTube and YouTube Music/subscriptions/subscriptions.csv\"), ਥੱਲੇ ਦਿੱਤੇ ਇੰਪੋਰਟ ਫਾਈਲ ਤੇ ਕਲਿੱਕ ਕਰਕੇ ਐਕਸਟਰੈਕਟ ਕੀਤੀ csv ਫਾਈਲ ਚੁਣੋ
+ URL ਜਾਂ ਆਪਣੀ ID ਟਾਈਪ ਕਰਕੇ ਸਾਉੰਡ ਕਲਾਉਡ ਪ੍ਰੋਫਾਈਲ ਇੰਪੋਰਟ ਕਰੋ: \n \n1. ਇੱਕ ਵੈਬ-ਬ੍ਰਾਊਜ਼ਰ ਵਿੱਚ \"ਡੈਸਕਟਾਪ ਮੋਡ\" ਨੂੰ ਚਾਲੂ ਕਰੋ (ਸਾਈਟ ਮੋਬਾਈਲ ਉਪਕਰਣਾਂ ਲਈ ਉਪਲਬਧ ਨਹੀਂ ਹੈ) \n2. ਇਸ URL ਤੇ ਜਾਓ: %1$s \n3. ਆਪਣੇ ਖਾਤੇ ਚ ਲੌਗ-ਇਨ ਕਰੋ \n4. ਨਿਰਦੇਸ਼ਤ ਕੀਤੇ ਗਏ ਪ੍ਰੋਫਾਈਲ URL ਨੂੰ ਕਾਪੀ ਕਰੋ।
ਤੁਹਾਡੀ ਆਈਡੀ, soundcloud.com/ਤੁਹਾਡੀ ਆਈਡੀ
- ਯਾਦ ਰੱਖੋ ਕਿ ਇਸ ਕਾਰਜ ਨਾਲ ਡਾਟਾ ਖਪਤ ਹੋ ਸਕਦਾ ਹੈ।
-\n
-\nਕੀ ਤੁਸੀਂ ਜਾਰੀ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ\?
+ ਯਾਦ ਰੱਖੋ ਕਿ ਇਸ ਕਾਰਜ ਨਾਲ ਡਾਟਾ ਖਪਤ ਹੋ ਸਕਦਾ ਹੈ।\n\nਕੀ ਤੁਸੀਂ ਜਾਰੀ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ?
ਪਲੇਅਬੈਕ ਸਪੀਡ ਕੰਟਰੋਲ
ਤਾਲ
ਪਿੱਚ
ਅਲਹਿਦਾ ਕਰੋ (ਵਿਗਾੜ ਪੈ ਸਕਦਾ ਹੈ)
ਕੀ ਤੁਸੀਂ ਸੈਟਿੰਗਾਂ ਨੂੰ ਵੀ ਇੰਪੋਰਟ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ\?
ਨਿਊਪਾਈਪ ਦੀ ਗੋਪਨੀਯਤਾ ਨੀਤੀ
- ਨਿਊਪਾਈਪ ਪ੍ਰੋਜੈਕਟ ਤੁਹਾਡੀ ਗੋਪਨੀਯਤਾ ਨੂੰ ਬਹੁਤ ਗੰਭੀਰਤਾ ਨਾਲ ਲੈਂਦਾ ਹੈ। ਇਸ ਲਈ ਐਪ ਤੁਹਾਡੀ ਸਹਿਮਤੀ ਤੋਂ ਬਿਨਾਂ ਕੋਈ ਵੀ ਡਾਟਾ ਇੱਕਠਾ ਨਹੀਂ ਕਰਦਾ।
-\nਨਿਊਪਾਈਪ ਦੀ ਗੋਪਨੀਯਤਾ ਨੀਤੀ ਵਿਸਥਾਰ ਵਿੱਚ ਦੱਸਦੀ ਹੈ ਕਿ ਜਦੋਂ ਤੁਸੀਂ ਕਰੈਸ਼ ਰਿਪੋਰਟ ਭੇਜਦੇ ਹੋ ਤਾਂ ਕਿਹੜਾ ਡਾਟਾ ਭੇਜਿਆ ਜਾਂ ਸਟੋਰ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।
+ ਨਿਊਪਾਈਪ ਪ੍ਰੋਜੈਕਟ ਤੁਹਾਡੀ ਗੋਪਨੀਯਤਾ ਨੂੰ ਬਹੁਤ ਗੰਭੀਰਤਾ ਨਾਲ ਲੈਂਦਾ ਹੈ। ਇਸ ਲਈ ਐਪ ਤੁਹਾਡੀ ਸਹਿਮਤੀ ਤੋਂ ਬਿਨਾਂ ਕੋਈ ਵੀ ਡਾਟਾ ਇੱਕਠਾ ਨਹੀਂ ਕਰਦਾ।\nਨਿਊਪਾਈਪ ਦੀ ਗੋਪਨੀਯਤਾ ਨੀਤੀ ਵਿਸਥਾਰ ਵਿੱਚ ਦੱਸਦੀ ਹੈ ਕਿ ਜਦੋਂ ਤੁਸੀਂ ਕਰੈਸ਼ ਰਿਪੋਰਟ ਭੇਜਦੇ ਹੋ ਤਾਂ ਕਿਹੜਾ ਡਾਟਾ ਭੇਜਿਆ ਜਾਂ ਸਟੋਰ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।
ਗੋਪਨੀਯਤਾ ਨੀਤੀ ਪੜ੍ਹੋ
- ਯੂਰਪੀਅਨ ਜਨਰਲ ਡੇਟਾ ਪ੍ਰੋਟੈਕਸ਼ਨ ਰੈਗੂਲੇਸ਼ਨ (ਜੀਡੀਪੀਆਰ) ਦੀ ਪਾਲਣਾ ਕਰਨ ਲਈ, ਅਸੀਂ ਤੁਹਾਡਾ ਧਿਆਨ ਨਿਊਪਾਈਪ ਦੀ ਗੋਪਨੀਯਤਾ ਨੀਤੀ ਵੱਲ ਖਿੱਚਦੇ ਹਾਂ। ਕਿਰਪਾ ਕਰਕੇ ਇਸਨੂੰ ਧਿਆਨ ਨਾਲ ਪੜ੍ਹੋ।
-\nਸਾਨੂੰ ਨੁਕਸ ਰਿਪੋਰਟ ਭੇਜਣ ਲਈ ਤੁਹਾਨੂੰ ਇਸ ਨੂੰ ਸਵੀਕਾਰ ਕਰਨਾ ਹੋਵੇਗਾ।
+ ਯੂਰਪੀਅਨ ਜਨਰਲ ਡੇਟਾ ਪ੍ਰੋਟੈਕਸ਼ਨ ਰੈਗੂਲੇਸ਼ਨ (ਜੀਡੀਪੀਆਰ) ਦੀ ਪਾਲਣਾ ਕਰਨ ਲਈ, ਅਸੀਂ ਤੁਹਾਡਾ ਧਿਆਨ ਨਿਊਪਾਈਪ ਦੀ ਗੋਪਨੀਯਤਾ ਨੀਤੀ ਵੱਲ ਖਿੱਚਦੇ ਹਾਂ। ਕਿਰਪਾ ਕਰਕੇ ਇਸਨੂੰ ਧਿਆਨ ਨਾਲ ਪੜ੍ਹੋ।\nਸਾਨੂੰ ਨੁਕਸ ਰਿਪੋਰਟ ਭੇਜਣ ਲਈ ਤੁਹਾਨੂੰ ਇਸ ਨੂੰ ਸਵੀਕਾਰ ਕਰਨਾ ਹੋਵੇਗਾ।
ਸਵੀਕਾਰ ਕਰੋ
ਅਸਵੀਕਾਰ
ਕੋਈ ਸੀਮਾ ਨਹੀਂ
@@ -458,7 +437,6 @@
ਰੇਡੀਓ
ਫੀਚਰਡ
ਇਹ ਸਮੱਗਰੀ ਸਿਰਫ਼ ਉਹਨਾਂ ਵਰਤੋਂਕਾਰਾਂ ਲਈ ਉਪਲਬਧ ਹੈ ਜਿੰਨ੍ਹਾਂ ਨੇ ਇਸਦੇ ਲਈ ਕੀਮਤ ਦਿੱਤੀ ਹੈ, ਇਸ ਕਰਕੇ ਨਿਊ-ਪਾਈਪ ਦੁਆਰਾ ਚਲਾਈ ਜਾਂ ਡਾਊਨਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।
- %s ਇਸਦਾ ਕਾਰਨ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ:
ਖਾਤਾ ਬੰਦ ਕੀਤਾ ਗਿਆ
ਇਹ ਵੀਡੀਓ ਸਿਰਫ਼ ਯੂਟਿਊਬ ਮਿਊਜ਼ਿਕ ਦੇ ਪ੍ਰੀਮੀਅਮ ਮੈਂਬਰਾਂ ਲਈ ਉਪਲਬਧ ਹੈ, ਇਸ ਕਰਕੇ ਨਿਊ-ਪਾਈਪ ਦੁਆਰਾ ਚਲਾਈ ਜਾਂ ਡਾਊਨਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।
ਇਹ ਸਮੱਗਰੀ ਨਿੱਜੀ (ਪ੍ਰਾਈਵੇਟ) ਹੈ, ਇਸ ਕਰਕੇ ਨਿਊ-ਪਾਈਪ ਦੁਆਰਾ ਚਲਾਈ ਜਾਂ ਡਾਊਨਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।
@@ -516,8 +494,7 @@
- %d ਸਕਿੰਟ
ਹਾਂ, ਅਤੇ ਅੱਧ-ਪਚੱਧੀਆਂ ਵੇਖੀਆਂ ਹੋਈਆਂ ਵੀ
- ਪਲੇਲਿਸਟ ਵਿੱਚ ਸ਼ਾਮਿਲ, ਪਹਿਲਾਂ ਚਾਹੇ ਬਾਅਦ ਵਿੱਚ ਵੇਖੇ ਜਾ ਚੁੱਕੇ ਵੀਡੀਓ ਹਟਾ ਦਿੱਤੇ ਜਾਣਗੇ।
-\nਕੀ ਵਾਕਿਆ ਹੀ ਤੁਸੀਂ ਇਹਨਾਂ ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ? ਇਸ ਕਾਰਵਾਈ ਨੂੰ ਵਾਪਸ ਨਹੀਂ ਮੋੜਿਆ ਜਾ ਸਕਣਾ!
+ ਪਲੇਲਿਸਟ ਵਿੱਚ ਸ਼ਾਮਿਲ ਪਹਿਲਾਂ ਤੇ ਬਾਅਦ ਵਿੱਚ ਵੇਖੇ ਜਾ ਚੁੱਕੇ ਵੀਡੀਓ ਹਟਾ ਦਿੱਤੇ ਜਾਣਗੇ। \nਕੀ ਵਾਕਿਆ ਹੀ ਤੁਸੀਂ ਇਹਨਾਂ ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ? ਇਸ ਕਾਰਵਾਈ ਨੂੰ ਵਾਪਸ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਣਾ!
ਵੇਖੇ ਹੋਏ ਵੀਡੀਓ ਹਟਾ ਦੇਈਏ\?
ਵੇਖੇ ਹੋਏ ਨੂੰ ਹਟਾਓ
ਸਿਸਟਮ ਡਿਫ਼ਾਲਟ
@@ -558,7 +535,7 @@
ਕੋਈ ਸਰੋਤਾ ਨਹੀਂ ਸੁਣ ਰਿਹਾ
ਕੋਈ ਦਰਸ਼ਕ ਨਹੀਂ ਵੇਖ ਰਿਹਾ
ਵੇਰਵਾ
- ਸਬੰਧਤ ਨਗ
+ ਸਬੰਧਤ ਆਈਟਮਾਂ
ਟਿੱਪਣੀਆਂ
ਗਿਟਹੱਬ \'ਤੇ ਜਾ ਕੇ ਇਤਲਾਹ ਦਿਓ
ਦੂਜੀਆਂ ਐਪਾਂ ਦੇ ਉੱਤੇ ਵਿਖਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ
@@ -826,10 +803,32 @@
ਸੈਕੰਡਰੀ
ਅਸਥਾਈ ਯੂਟਿਊਬ ਪਲੇਲਿਸਟ ਵਜੋਂ ਸਾਂਝਾ ਕਰੋ
ਪਲੇਲਿਸਟਾਂ
- %1$s ਦੀ ਖੋਜ ਕਰੋ
- %1$s (%2$s) ٪1$s ਦੀ ਖੋਜ ਕਰੋ
+ %1$s ਖੋਜੋ
+ %1$s (%2$s) ਖੋਜੋ
ਫੀਡ ਗਰੁੱਪ ਚੁਣੋ
ਅਜੇ ਤੱਕ ਕੋਈ ਫੀਡ ਗਰੁੱਪ ਨਹੀਂ ਬਣਾਇਆ ਗਿਆ
ਚੈਨਲ ਗਰੁੱਪ ਪੰਨਾ
ਪਸੰਦ
+ ਫ਼ਾਈਲ ਮਿਟਾਓ
+ ਐਂਟਰੀ ਮਿਟਾਓ
+ ਖ਼ਾਤਾ ਬੰਦ ਕੀਤਾ ਗਿਆ\n\n%1$s ਇਹ ਕਾਰਨ ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ: %2$s
+ ਐਂਟਰੀ ਮਿਟਾ ਦਿੱਤੀ ਗਈ
+ ਪੌਪਅੱਪ ਪਲੇਅਰ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ, ਕਿਰਪਾ ਕਰਕੇ ਹੇਠਾਂ ਦਿੱਤੇ Android ਸੈਟਿੰਗ ਮੀਨੂ ਵਿੱਚ %1$s ਚੁਣੋ ਅਤੇ %2$s ਨੂੰ ਇਨੇਬਲ ਕਰੋ।
+ \"ਹੋਰ ਐਪਾਂ ਉੱਤੇ ਡਿਸਪਲੇ ਦੀ ਆਗਿਆ ਦਿਓ\"
+ %sਹਜ਼ਾਰ
+ %sਮਿਲੀਅਨ
+ %sਅਰਬ
+ SoundCloud ਟੌਪ 50 ਪੰਨਾ ਹਟਾ ਦਿੱਤਾ ਗਿਆ
+ SoundCloud ਨੇ ਮੂਲ ਟੌਪ 50 ਚਾਰਟਾਂ ਨੂੰ ਬੰਦ ਕਰ ਦਿੱਤਾ ਹੈ। ਸੰਬੰਧਿਤ ਟੈਬ ਨੂੰ ਤੁਹਾਡੇ ਮੁੱਖ ਪੰਨੇ ਤੋਂ ਹਟਾ ਦਿੱਤਾ ਗਿਆ ਹੈ।
+ YouTube ਸੰਯੁਕਤ ਰੁਝਾਨ ਹਟਾਇਆ ਗਿਆ
+ YouTube ਨੇ 21 ਜੁਲਾਈ 2025 ਤੋਂ ਸੰਯੁਕਤ \"ਰੁਝਾਨ ਵਿੱਚ\" ਪੰਨੇ ਨੂੰ ਬੰਦ ਕਰ ਦਿੱਤਾ ਹੈ। NewPipe ਨੇ ਡਿਫ਼ਾਲਟ \"ਰੁਝਾਨ ਵਿੱਚ\" ਪੰਨੇ ਨੂੰ ਟ੍ਰੈਂਡਿੰਗ ਲਾਈਵਸਟ੍ਰੀਮਾਂ ਨਾਲ ਬਦਲ ਦਿੱਤਾ ਹੈ।\n\nਤੁਸੀਂ \"ਸੈਟਿੰਗਾਂ > ਸਮੱਗਰੀ > ਮੁੱਖ ਪੰਨੇ ਦੀ ਸਮੱਗਰੀ\" ਵਿੱਚ ਵੱਖ-ਵੱਖ ਟ੍ਰੈਂਡਿੰਗ ਪੰਨਿਆਂ ਨੂੰ ਵੀ ਚੁਣ ਸਕਦੇ ਹੋ।
+ ਗੇਮਿੰਗ ਟ੍ਰੈਂਡਸ
+ ਟ੍ਰੈਂਡਿੰਗ ਪੌਡਕਾਸਟ
+ ਟਰੈਂਡਿੰਗ ਫ਼ਿਲਮਾਂ ਅਤੇ ਸ਼ੋਅ
+ ਟਰੈਂਡਿੰਗ ਸੰਗੀਤ
+ ਪਲੇਅ ਕਰਦੇ ਸਮੇਂ ਸਰਵਰ ਤੋਂ HTTP error 403 ਪ੍ਰਾਪਤ ਹੋਇਆ, ਜੋ ਸ਼ਾਇਦ ਸਟ੍ਰੀਮਿੰਗ URL ਦੀ ਮਿਆਦ ਪੁੱਗਣ ਜਾਂ IP ਦੀ ਪਾਬੰਦੀ ਕਾਰਨ ਹੋਈ ਹੈ
+ ਚਲਾਉਣ ਦੌਰਾਨ ਸਰਵਰ ਤੋਂ HTTP error %1$s ਪ੍ਰਾਪਤ ਹੋਇਆ
+ ਪਲੇਅ ਕਰਦੇ ਸਮੇਂ ਸਰਵਰ ਤੋਂ HTTP error 403 ਪ੍ਰਾਪਤ ਹੋਇਆ, ਜੋ ਸ਼ਾਇਦ IP ਬੈਨ ਜਾਂ ਸਟ੍ਰੀਮਿੰਗ URL ਡੀਔਬਫਸਕੇਸ਼ਨ ਸਮੱਸਿਆਵਾਂ ਕਾਰਨ ਹੋਈ ਹੈ
+ %1$s ਨੇ ਡੇਟਾ ਪ੍ਰਦਾਨ ਕਰਨ ਤੋਂ ਇਨਕਾਰ ਕਰ ਦਿੱਤਾ, ਅਤੇ ਇਹ ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਲੌਗਇਨ ਕਰਨ ਲਈ ਕਿਹਾ ਕਿ ਬੇਨਤੀਕਰਤਾ ਬੋਟ ਨਹੀਂ ਹੈ।\n\nਹੋ ਸਕਦਾ ਹੈ ਕਿ %1$s ਨੇ ਤੁਹਾਡੇ IP ਨੂੰ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਈ ਹੋਵੇ, ਤੁਸੀਂ ਕੁਝ ਸਮਾਂ ਉਡੀਕ ਕਰ ਸਕਦੇ ਹੋ ਜਾਂ ਕਿਸੇ ਵੱਖਰੇ IP \'ਤੇ ਸਵਿੱਚ ਕਰ ਸਕਦੇ ਹੋ (ਉਦਾਹਰਣ ਵਜੋਂ VPN ਨੂੰ ਚਾਲੂ/ਬੰਦ ਕਰਕੇ, ਜਾਂ WiFi ਤੋਂ ਮੋਬਾਈਲ ਡੇਟਾ \'ਤੇ ਸਵਿੱਚ ਕਰਕੇ)।
+ ਇਹ ਸਮੱਗਰੀ ਵਰਤਮਾਨ ਵਿੱਚ ਚੁਣੇ ਗਏ ਦੇਸ਼ ਦੀ ਸਮੱਗਰੀ ਲਈ ਉਪਲੱਬਧ ਨਹੀਂ ਹੈ।\n\n\"ਸੈਟਿੰਗਾਂ > ਸਮੱਗਰੀ > ਡਿਫ਼ਾਲਟ ਸਮੱਗਰੀ ਦੇਸ਼\" ਤੋਂ ਆਪਣੀ ਚੋਣ ਬਦਲੋ।
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index a0c68f942..3eee59c46 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -96,10 +96,7 @@
Wszystkie
Wyłączone
Wyczyść
- tys.
- mln
- mld
- To pozwolenie jest wymagane, aby
+ To pozwolenie jest wymagane, aby
\notworzyć w trybie okienkowym
Otwórz w trybie okienkowym
Tryb okienkowy
@@ -595,8 +592,8 @@
Zepsuj aplikację
Ta treść dostępna jest tylko dla użytkowników, którzy za nią zapłacili. Nie może być strumieniowana ani pobierana przez NewPipe.
To wideo dostępne jest tylko dla subskrybentów usługi YouTube Music Premium. Nie może być strumieniowane ani pobierane przez NewPipe.
- Ta treść jest prywatna, więc nie może być strumieniowana ani pobierana przez NewPipe
- Ta treść nie jest dostępna w Twoim kraju
+ Ta treść jest prywatna, więc nie może być strumieniowana ani pobierana przez NewPipe.
+ Ta treść nie jest dostępna w Twoim kraju.
To wideo jest objęte ograniczeniem wiekowym.
\nZe względu na nowe zasady YouTube dotyczące wideo z ograniczeniami wiekowymi NewPipe nie może uzyskać dostępu do żadnego z jego strumieni wideo i dlatego nie jest w stanie go odtworzyć.
To jest utwór SoundCloud Go+ (przynajmniej w Twoim kraju). Nie może być strumieniowany ani pobierany przez NewPipe.
@@ -626,8 +623,7 @@
Kategoria
Otwórz stronę
Teraz możesz zaznaczyć tekst wewnątrz opisu. Pamiętaj, że w trybie zaznaczania strona może migotać i linki nie będą klikalne.
- %s podaje ten powód:
- Konto zamknięte
+ Konto zamknięte.
Tryb szybki dla ładowania kanału nie dostarcza więcej informacji na ten temat.
Konto autora zostało zawieszone.
\nNewPipe nie będzie w stanie załadować tego kanału w przyszłości.
@@ -857,4 +853,24 @@
Polubienia
Usunięto stronę SoundCloud 50 najlepszych
SoundCloud wycofał oryginalną listę 50 najlepszych. Odpowiadająca karta została usunięta ze strony głównej.
+ Usunięto połączone Na czasie YouTube
+ Od 21 lipca 2025 r. YouTube zaprzestał korzystania z połączonego Na czasie. NewPipe zastąpił domyślną stronę Na czasie popularnymi transmisjami na żywo.\n\nMożesz także wybrać różne strony Na czasie w „Ustawienia > Zawartość > Zawartość strony głównej”.
+ Gry na czasie
+ Podcasty na czasie
+ Filmy i programy na czasie
+ Muzyka na czasie
+ %stys.
+ %smln
+ %smld
+ Usuń plik
+ Usuń wpis
+ Usunięto wpis
+ Aby korzystać z odtwarzacza w trybie okienkowym, wybierz %1$s w następującym menu ustawień Androida i włącz %2$s.
+ „Zezwól na wyświetlanie nad innymi aplikacjami”
+ Konto zamknięte.\n\n%1$s podaje następujący powód: %2$s
+ Podczas odtwarzania otrzymano od serwera błąd HTTP 403, prawdopodobnie spowodowany wygaśnięciem adresu URL strumienia lub blokadą adresu IP.
+ Podczas odtwarzania otrzymano od serwera błąd HTTP %1$s.
+ Podczas odtwarzania otrzymano od serwera błąd HTTP 403, prawdopodobnie spowodowany blokadą adresu IP lub problemami z odszyfrowaniem adresu URL strumienia.
+ %1$s odmówił dostarczenia danych, prosząc o zalogowanie się w celu potwierdzenia, że nie jest się botem.\n\nTwoje IP mogło zostać tymczasowo zablokowane przez %1$s. Możesz chwilę poczekać lub zmienić adres IP (na przykład włączając/wyłączając VPN lub przełączając się z sieci Wi-Fi na dane komórkowe).
+ Ta treść nie jest dostępna dla aktualnie wybranego kraju treści.\n\nZmień swój wybór w „Ustawienia > Zawartość > Domyślny kraj treści”.
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index 56731cb06..a0ec8127e 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -90,9 +90,6 @@
Reproduzindo em modo Popup
Todos
Desativado
- mil
- mi
- bi
Essa permissão é necessária
\npara abrir em modo Popup
Limpar
@@ -622,7 +619,6 @@
Ativar seleção de texto na descrição
Agora você pode selecionar o texto dentro da descrição. Note que a página pode piscar e os URL podem não ser clicáveis no modo de seleção.
Abrir site
- %s fornece este motivo:
Conta encerrada
O modo feed rápido não fornece mais informações sobre isso.
A conta do autor foi encerrada.
@@ -843,9 +839,29 @@
Selecione um grupo de feeds
Nenhum grupo de feeds criado ainda
Página do grupo do canal
- Pesquisar %1$s
- Pesquisar %1$s (%2$s)
+ Buscar %1$s
+ Buscar %1$s (%2$s)
Curtidas
Página Top 50 do SoundCloud removida
O SoundCloud descontinuou as paradas originais do Top 50. A aba correspondente foi removida da sua página principal.
+ Para usar o Popup Player, selecione %1$s no seguinte menu de configurações do Android e ative %2$s.
+ “Permitir exibição sobre outros aplicativos”
+ %sK
+ %sM
+ %sB
+ Excluir arquivo
+ Excluir entrada
+ Tendências combinadas do YouTube removidas
+ O YouTube descontinuou a página de tendências combinadas em 21 de julho de 2025. O NewPipe substituiu a página de tendências padrão pelas transmissões ao vivo em alta.\n\nVocê também pode selecionar páginas de tendências diferentes em \"Configurações > Conteúdo > Conteúdo da página principal\".
+ Jogos em alta
+ Podcasts em alta
+ Filmes e programas em alta
+ Músicas em alta
+ Entrada excluída
+ Conta encerrada\n\n%1$s informa este motivo: %2$s
+ Erro HTTP 403 recebido do servidor durante a reprodução, provavelmente causado por URL de streaming expirado ou IP banido
+ Erro HTTP %1$s recebido do servidor durante reprodução
+ Erro HTTP 403 recebido do servidor durante a reprodução, provavelmente causado por um banimento de IP ou problemas de desofuscação de URL de streaming
+ %1$s se recusou a fornecer dados, solicitando um login para confirmar que o solicitante não é um bot.\n\nSeu IP pode ter sido temporariamente banido por %1$s. Você pode esperar um pouco ou mudar para um IP diferente (por exemplo, ativando/desativando uma VPN ou alternando de Wi-Fi para dados móveis).
+ Este conteúdo não está disponível para o país selecionado atualmente.\n\nAltere sua seleção acessando “Configurações > Conteúdo > País padrão do conteúdo”.
diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml
index f670aa52e..1ec01b0d7 100644
--- a/app/src/main/res/values-pt-rPT/strings.xml
+++ b/app/src/main/res/values-pt-rPT/strings.xml
@@ -229,7 +229,6 @@
OK
Não foi possível atualizar a subscrição
Sim e também os vídeos parcialmente vistos
- M
Ainda não há listas de reprodução favoritas
- %s ouvinte
@@ -423,8 +422,6 @@
Importado
Automático
Substitui o seu histórico, subscrições, listas de reprodução e (opcionalmente) definições
- k
- MM
Remover marcador
Útil ao trocar para dados móveis, mas algumas transferências não podem ser suspensas
Toque longo para colocar na fila
@@ -626,7 +623,6 @@
Desativar seleção de texto na descrição
Ativar seleção de texto na descrição
Agora pode selecionar o texto na descrição. Note que a página pode cintilar e as ligações podem não ser clicáveis enquanto estiver no modo de seleção.
- %s fornece este motivo:
Conta encerrada
O modo de feed rápido não fornece mais informações sobre isto.
A conta do autor foi encerrada.
@@ -845,4 +841,27 @@
Página do grupo do canal
Pesquisar %1$s
Pesquisar %1$s (%2$s)
+ Gostos
+ Página Top 50 do SoundCloud removida
+ O SoundCloud descontinuou os gráficos originais do Top 50. A guia correspondente foi removida da sua página principal.
+ Tendência combinada do YouTube removida
+ O YouTube descontinuou a página de tendência combinada a partir de 21 de julho de 2025. O NewPipe substituiu a página de tendência predefinida com as streams ao vivo de tendência.\n\nTambém pode escolher páginas de tendência diferentes em \"Definições > Conteúdo > Conteúdo da página principal\".
+ Tendências de jogos
+ Tendências de podcasts
+ Tendências de filmes e shows
+ Tendências de música
+ %sK
+ %sM
+ %sB
+ Para usar o reprodutor pop-up, escolhe %1$s no menu seguinte de configurações do Android e ative %2$s.
+ “Permitir exibição sobre outras apps”
+ Apagar ficheiro
+ Apagar entrada
+ Entrada apagada
+ Conta terminada\n\n%1$s fornece esta razão: %2$s
+ Erro HTTP %1$s recebido do servidor ao reproduzir
+ %1$s recusou fornecer dados, pedindo por um login para confirmar que o solicitante não é um bot.\n\nO seu IP pode ter sido temporariamente banido por %1$s, pode esperar algum tempo ou mudar para um IP diferente (por exemplo, a ligar / desligar uma VPN, ou a alternar de Wi-Fi para dados móveis).
+ Este conteúdo não está disponível para o país de conteúdo atualmente selecionado.\n\nAltere a sua seleção de \"Configurações > Conteúdo > País predefinido de conteúdo\".
+ Erro HTTP 403 recebido do servidor durante a reprodução, provavelmente causado pela URL de streaming expirado ou IP banido
+ Erro HTTP 403 recebido do servidor durante a reprodução, provavelmente causado por um bloqueio de IP ou problemas de desofuscação da URL de streaming
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index 72c6b62da..da54067e7 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -82,9 +82,6 @@
Abrir no modo popup
Preto
Tudo
- K
- M
- MM
Esta permissão é necessária
\npara o modo popup
Desafio reCAPTCHA
@@ -608,7 +605,6 @@
Desativar túnel multimédia
Sempre que descarregar um ficheiro, terá que indicar o local para o guardar
Ainda não definiu uma pasta para as descargas. Escolha agora a pasta a utilizar
- %s fornece este motivo:
Conta encerrada
O modo de fonte rápida não fornece mais informações sobre isto.
A conta do autor foi encerrada.
@@ -845,4 +841,27 @@
Página do grupo do canal
Pesquisar %1$s
Pesquisar %1$s (%2$s)
+ Gostos
+ Página Top 50 do SoundCloud removida
+ O SoundCloud descontinuou os gráficos originais do Top 50. A guia correspondente foi removida da sua página principal.
+ Tendência combinada do YouTube removida
+ O YouTube descontinuou a página de tendência combinada a partir de 21 de julho de 2025. O NewPipe substituiu a página de tendência predefinida com as streams ao vivo de tendência.\n\nTambém pode escolher páginas de tendência diferentes em \"Definições > Conteúdo > Conteúdo da página principal\".
+ Tendências de jogos
+ Tendências de podcasts
+ Tendências de filmes e shows
+ Tendências de música
+ %sK
+ %sM
+ %sB
+ Para usar o reprodutor pop-up, escolhe %1$s no menu seguinte de configurações do Android e ative %2$s.
+ “Permitir exibição sobre outras apps”
+ Apagar ficheiro
+ Apagar entrada
+ Entrada apagada
+ Conta terminada\n\n%1$s fornece esta razão: %2$s
+ Erro HTTP %1$s recebido do servidor ao reproduzir
+ %1$s recusou fornecer dados, pedindo por um login para confirmar que o solicitante não é um bot.\n\nO seu IP pode ter sido temporariamente banido por %1$s, pode esperar algum tempo ou mudar para um IP diferente (por exemplo, a ligar / desligar uma VPN, ou a alternar de Wi-Fi para dados móveis).
+ Este conteúdo não está disponível para o país de conteúdo atualmente selecionado.\n\nAltere a sua seleção de \"Configurações > Conteúdo > País predefinido de conteúdo\".
+ Erro HTTP 403 recebido do servidor durante a reprodução, provavelmente causado pela URL de streaming expirado ou IP banido
+ Erro HTTP 403 recebido do servidor durante a reprodução, provavelmente causado por um bloqueio de IP ou problemas de desofuscação da URL de streaming
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
index cda82bd25..1b7210e58 100644
--- a/app/src/main/res/values-ro/strings.xml
+++ b/app/src/main/res/values-ro/strings.xml
@@ -92,9 +92,6 @@
Dezactivat
Aplicația/UI s-a oprit
Ce:\\nSolicitare:\\nLimba conținutului:\\nȚara conținutului:\\nLimba aplicației:\\nServiciu:\\nOra GMT:\\nPachet:\\nVersiune:\\nVersiune SO:
- k
- mil.
- mld.
Elimină sunetul audio la anumite rezoluții
Fundal
Pop-up
@@ -627,7 +624,6 @@
Dezactivați selectarea textului în descriere
Activați selectarea textului în descriere
Acum puteți selecta text în interiorul descrierii. Rețineți că este posibil ca pagina să pâlpâie, iar linkurile să nu poată fi accesate în modul de selecție.
- %s oferă acest motiv:
Contul a fost închis
Modul rapid nu furnizează mai multe informații în acest sens.
Contul autorului a fost închis.
@@ -848,4 +844,8 @@
Aprecieri
Pagina SoundCloud Top 50 a fost eliminată
SoundCloud a eliminat Top 50. Fila corespunzătoare a fost eliminată din pagina principală.
+ „Permite afișarea deasupra altor aplicații”
+ %s mii
+ %s mil.
+ %s mld.
diff --git a/app/src/main/res/values-rom/strings.xml b/app/src/main/res/values-rom/strings.xml
new file mode 100644
index 000000000..55344e519
--- /dev/null
+++ b/app/src/main/res/values-rom/strings.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 8b54adaad..e3ca674a2 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -94,9 +94,6 @@
Выберите отображаемые предложения поиска
Отключено
Убирает звук в некоторых разрешениях
- млн
- млрд
- тыс.
Разрешение всплывающего окна
Помнить последние размер и позицию всплывающего окна
Предложения поиска
@@ -636,7 +633,6 @@
Не удалось загрузить подписку \'%s\'.
Ошибка загрузки подписки
Открыть веб-сайт
- %s указывает следующую причину:
Аккаунт отключён
Начиная с Android 10 поддерживается только «Storage Access Framework»
Спрашивать, куда сохранять каждую загрузку
@@ -853,4 +849,24 @@
Лайки
Страница SoundCloud Top 50 удалена
SoundCloud прекратил поддерживать оригинальные чарты Top 50. Соответствующая вкладка была удалена с вашей главной страницы.
+ %sК
+ %sмлн
+ %sмлрд
+ Игровые тренды
+ Удалены объединённые тренды YouTube
+ YouTube прекратил поддержку объединённой страницы трендов 21 июля 2025 года. NewPipe заменил страницу трендов по умолчанию на тренды в прямых трансляциях.\n\nВы также можете выбрать другие страницы трендов в \"Настройки > Контент > Главная страница\".
+ Тренды в подкастах
+ Тренды в фильмах и шоу
+ Тренды в музыке
+ Чтобы использовать Popup Player, выберите %1$s в следующем меню настроек Android и включите %2$s.
+ «Разрешить отображение поверх других приложений»
+ Удалить файл
+ Удалить запись
+ Учётная запись закрыта\n\n%1$s указал причину: %2$s
+ Запись удалена
+ Во время воспроизведения получена ошибка HTTP 403 от сервера, вероятно, вызванная истечением срока действия URL-адреса потоковой передачи или блокировкой IP-адреса
+ Ошибка HTTP %1$s получена от сервера во время воспроизведения
+ Во время воспроизведения получена ошибка HTTP 403 от сервера, вероятно, вызванная блокировкой IP-адреса или проблемами деобфускации URL-адреса потоковой передачи
+ %1$s отказался предоставить данные, запросив логин для подтверждения, что запросчик не бот.\n\nВозможно, ваш IP-адрес временно заблокирован %1$s. Вы можете подождать некоторое время или переключиться на другой IP-адрес (например, включив/выключив VPN или переключившись с Wi-Fi на мобильный интернет).
+ Этот контент недоступен для выбранной страны контента.\n\nИзмените свой выбор в разделе «Настройки > Контент > Страна контента по умолчанию».
diff --git a/app/src/main/res/values-ryu/strings.xml b/app/src/main/res/values-ryu/strings.xml
index 1bc89420c..e9baa11da 100644
--- a/app/src/main/res/values-ryu/strings.xml
+++ b/app/src/main/res/values-ryu/strings.xml
@@ -83,9 +83,6 @@
reCAPTCHAようきゅうさびたん
ブラック
まじり
- k
- M
- B
ポップアップモードっしふぃらちゅん
ポップアップモードっしふぃらちゅんがー
\nきんぎんぬきょかがふぃちようでぃす
@@ -625,7 +622,6 @@
オフ
オン
タブレットモード
- %sやしがくぬりゆうていじ:
ひょうじさん
ていふぃんしち(しょう)
かんふぃんしち(だい)
diff --git a/app/src/main/res/values-sat/strings.xml b/app/src/main/res/values-sat/strings.xml
index a3ed7c405..717283e83 100644
--- a/app/src/main/res/values-sat/strings.xml
+++ b/app/src/main/res/values-sat/strings.xml
@@ -216,8 +216,6 @@
ᱡᱟᱦᱟᱱ ᱡᱤᱱᱤᱥ
ᱱᱚᱣᱟ ᱨᱮᱫᱚ ᱡᱟᱹᱥᱛᱤ ᱡᱟᱹᱥᱛᱤ ᱠᱨᱤᱠᱮᱴ ᱢᱮᱱᱟᱜᱼᱟ ᱾
ᱵᱷᱤᱰᱤᱭᱳ
- k
- M
ᱥᱮᱞᱮᱫᱤᱭᱟᱹ ᱠᱚᱣᱟᱜ ᱞᱮᱠᱷᱟ ᱵᱟᱭ ᱦᱟᱹᱴᱤᱧ ᱟᱠᱟᱱᱟ
ᱵᱟᱱᱩᱜ ᱧᱮᱞ
ᱵᱷᱤᱰᱤᱭᱳ ᱵᱟᱹᱱᱩᱜᱼᱟ
@@ -333,7 +331,6 @@
ᱪᱮᱯᱴᱟᱨᱥ
ᱞᱟᱹᱠᱛᱤ ᱠᱟᱱᱟ ᱟᱢ ᱢᱤᱫ ᱯᱷᱤᱞ ᱢᱟᱱᱮᱡᱚᱨ ᱤᱱᱥᱴᱚᱞ ᱢᱮ ᱟᱨᱵᱟᱝ ᱰᱟᱩᱱᱞᱚᱰ ᱥᱤᱴᱤᱝ ᱨᱮ ᱵᱚᱫᱚᱞ ᱦᱚᱪᱚ ᱞᱟᱹᱜᱤᱫ ᱯᱨᱚᱵᱷᱟᱣ ᱢᱮ\"
ᱱᱚᱶᱟ ᱵᱷᱤᱰᱤᱭᱳ ᱫᱚ ᱭᱩᱴᱭᱩᱵᱽ ᱢᱤᱣᱡᱤᱠ ᱯᱨᱤᱢᱤᱭᱟᱢ ᱥᱮᱞᱮᱫᱤᱭᱟᱹ ᱠᱚ ᱞᱟᱹᱜᱤᱫ ᱜᱮ ᱧᱟᱢᱚᱜᱼᱟ, ᱚᱱᱟᱛᱮ ᱱᱚᱶᱟ ᱫᱚ ᱱᱤᱭᱩ ᱯᱟᱭᱤᱯ ᱦᱚᱛᱮᱛᱮ ᱵᱟᱝ ᱥᱴᱨᱤᱢ ᱟᱨ ᱵᱟᱝ ᱰᱟᱩᱱᱞᱳᱰ ᱦᱩᱭ ᱫᱟᱲᱮᱭᱟᱜᱼᱟ ᱾
- %s ᱫᱚ ᱱᱚᱶᱟ ᱞᱟᱹᱠᱛᱤ ᱠᱟᱱᱟ:
ᱚᱴᱚᱢᱟᱴᱤᱠ (ᱰᱤᱵᱟᱤᱥ ᱛᱷᱮᱢ)
ᱟᱢᱟᱜ ᱯᱩᱭᱞᱩ ᱧᱤᱫᱟᱹ ᱛᱷᱤᱢ ᱵᱟᱪᱷᱟᱣ ᱢᱮ ⁇ %s
ᱟᱢ ᱞᱟᱛᱟᱨ ᱨᱮ ᱟᱢᱟᱜ ᱧᱤᱫᱟᱹ ᱪᱮᱛᱟᱱ ᱵᱟᱪᱷᱟᱣ ᱫᱟᱲᱮᱭᱟᱜ ᱟ
@@ -478,7 +475,6 @@
ᱱᱟᱣᱟ ᱟᱹᱨᱡᱤ ᱞᱟᱹᱜᱤᱫ ᱟᱹᱪᱩᱨ ᱢᱮ
ᱚᱰᱤᱭᱳ
ᱟᱨᱦᱚᱸ ᱯᱟᱲᱦᱟᱣ ᱢᱮ
- ᱵᱤ
ᱱᱤᱛᱚᱜ ᱵᱟᱪᱷᱟᱣ ᱟᱠᱟᱱ ᱴᱳᱜᱞ ᱥᱮᱵᱟ:
ᱚᱵᱷᱤᱱᱮᱛᱟᱨ ᱵᱟᱹᱱᱩᱜᱼᱟ
ᱚᱠᱚᱭ ᱦᱚᱸ ᱵᱟᱝ ᱧᱮᱞᱚᱜ ᱠᱟᱱᱟ
diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml
index 0c42f1ef0..091001ae6 100644
--- a/app/src/main/res/values-sc/strings.xml
+++ b/app/src/main/res/values-sc/strings.xml
@@ -165,9 +165,6 @@
Perunu iscritu
Allughe/istuda su servìtziu. Ischertadu como:
- Mrd
- Mlln
- mìg
Torra a proare
Àudio
Vìdeu
@@ -613,7 +610,6 @@
Como podes ischertare su testu in intro de sa descritzione. Ammenta·ti chi sa pàgina diat pòdere trèmere e sos ligàmenes si diant pòdere no abèrrere cando ses in modalidade de ischerta.
Incumintzende dae Android 10 petzi sa \'Storage Access Framework\' (Istrutura de Atzessu a s\'Archiviatzione) est suportada
Aberi su situ web
- %s frunit custa resone:
Contu serradu
Su recùperu lestru de sos flussos non frunit àteras informatziones in subra de custu.
Su contu de s\'autore l\'ant serradu.
@@ -826,4 +822,18 @@
Iscalitas
Cumpartzi comente un\'iscalita temporànea de YouTube
segundàriu
+ Chirca in %1$s
+ Chirca %1$s (%2$s)
+ Seletziona unu grupu de flussos
+ Galu perunu grupu de flussos creadu
+ Pàgina de grupu de canales
+ Agradessimentos
+ Pàgina Top 50 de SoundCloud bogada
+ SoundCloud at abbandonadu sos gràficos Top 50 originales. S\'ischeda currispondente est istada bogada dae sa pàgina printzipale tua.
+ Tendèntzias cumbinadas de YouTube bogadas
+ YouTube at abbandonadu sa pàgina de sas tendèntzias cumbinadas in su 21 de trìulas de su 2025. NewPipe at sostituidu sa pàgina de sas tendèntzias printzipales cun sas diretas de tendèntzia.\n\nPodes fintzas seletzionare pàginas de sas tendèntzias diferentes in \"Impostatziones > Cuntenutos > Cuntenutu de sa pàgina printzipale\".
+ Giogos de tendèntzia
+ Podcasts de tendèntzia
+ Films e programmas de tendèntzia
+ Mùsica de tendèntzia
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index 3bae642c7..601623cb1 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -45,7 +45,7 @@
Náhľad avataru uploadera
Lajky
Dislajky
- Začnite klepnutím na lupu.
+ Začnite ťuknutím na lupu.
Obsah
Zobraziť vekovo obmedzený obsah
Naživo
@@ -74,7 +74,7 @@
Čakajte prosím…
Skopírované do schránky
Priečinok na sťahovanie zadefinujte prosím neskôr v nastaveniach
- Sťahované súbory
+ Stiahnuté súbory
Stiahnuté
Hlásenie o chybe
Aplikácia/UP zlyhalo
@@ -82,9 +82,6 @@
Výzva reCAPTCHA
Čierna
Všetko
- k
- M
- B
Požiadavka reCAPTCHA
Otvoriť vo vyskakovacom okne
Tieto práva sú potrebné pre
@@ -211,7 +208,7 @@
Neplatný ZIP súbor
Upozornenie: Nemožno importovať všetky súbory.
Toto prepíše vaše aktuálne nastavenie.
- Trendy
+ Populárne
Top 50
Nové a horúce
Odstrániť
@@ -476,7 +473,7 @@
- %d dní
Skupiny kanálov
- Zdroj naposledy aktualizovaný: %s
+ Zdroj aktualizovaný: %s
Nenačítané: %d
Načítavanie zdroja…
Spracovávanie zdroja…
@@ -489,7 +486,7 @@
Bez názvu skupiny
Chcete zmazať vybranú skupinu\?
- Nová
+ Nový
Zdroj
Interval obnovy zdroja
Čas od poslednej aktualizácie, kedy sa odber považuje za neaktuálny - %s
@@ -621,7 +618,6 @@
Povolenie výberu textu v popise
Teraz môžete vybrať text vo vnútri popisu. Upozorňujeme, že stránka môže blikať a odkazy nemusia byť klikateľné, keď je v režime výberu.
Otvoriť webstránku
- %s uvádza tento dôvod:
Účet bol zrušený
Tento rýchly režim neposkytuje viac informácií.
Účet autora bol zrušený.
@@ -728,7 +724,7 @@
Používate najnovšiu verziu NewPipe
Táto možnosť je dostupná len pre motív %s
Rýchly režim
- Import alebo export odberov z 3-bodkovej ponuky
+ Importujte alebo exportujte odbery v menu s 3-mi bodkami
Akcia gesta vľavo
Vyberte gesto pre pravú polovicu obrazovky prehrávača
Akcia gesta vpravo
@@ -847,4 +843,24 @@
Páči sa
SoundCloud Top 50 stránka odstránená
SoundCloud prestal používať pôvodnú Top 50. Daná stránka bola odstránená z hlavnej stránky.
+ Odstránené kombinované trendy na YouTube
+ YouTube ukončil prevádzku kombinovanej stránky s trendmi k 21. júlu 2025. NewPipe nahradil predvolenú stránku s trendmi stránkou s trendovými živými prenosmi.\n\nV nastaveniach „Nastavenia > Obsah > Obsah hlavnej stránky“ môžete vybrať aj iné stránky s trendmi.
+ Populárne hry
+ Populárne podcasty
+ Populárne filmy a seriály
+ Populárna hudba
+ %stis.
+ %smil.
+ %smld.
+ Položka vymazaná
+ Vymazať položku
+ \"Povoliť zobrazenie cez iné aplikácie\"
+ Vymazať súbor
+ Ak chcete používať Popup Player, vyberte %1$s v nasledujúcej ponuke nastavení Androidu a povoľte %2$s.
+ Účet bol zrušený\n\n%1$s uvádza tento dôvod: %2$s
+ Počas prehrávania bola zo servera prijatá chyba HTTP 403, pravdepodobne spôsobená vypršaním platnosti streamingovej adresy URL alebo zákazom IP adresy
+ Chyba HTTP %1$s prijatá zo servera počas prehrávania
+ Chyba HTTP 403 prijatá zo servera počas prehrávania, pravdepodobne spôsobená zákazom IP adresy alebo problémami s deobfuskáciou streamingovej URL adresy
+ %1$s odmietol poskytnúť údaje, žiada o prihlásenie na potvrdenie, že žiadateľ nie je bot.\n\nVaša IP adresa mohla byť dočasne zakázaná %1$s, môžete nejaký čas počkať alebo prejsť na inú IP adresu (napríklad zapnutím/vypnutím VPN alebo prepnutím z WiFi na mobilné dáta).
+ Tento obsah nie je dostupný pre aktuálne zvolenú krajinu obsahu.\n\nZmeňte výber v ponuke \"Nastavenia > Obsah > Predvolená krajina obsahu\".
diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml
index 68875fe23..8b4ba8f7b 100644
--- a/app/src/main/res/values-sl/strings.xml
+++ b/app/src/main/res/values-sl/strings.xml
@@ -83,9 +83,6 @@
Predmet:\\nZahteva:\\nJezik vsebine:\\nDržava vsebine:\\nJezik aplikacije:\\nStoritev:\\nČas v GMT:\\nPaket:\\nRazličica:\\nRazličica OS:
Črna
Vse
- k
- mio
- mrd
Odpri v pojavnem načinu
To dovoljenje je potrebno za odpiranje
\nv pojavnem načinu
@@ -264,7 +261,7 @@
NewPipe-ovi pravilnik zasebnosti
Obiščite spletno mesto od NewPipe za več informacij in novic.
Končano
- Ni komantarjev
+ Ni komentarjev
Nobeden ne posluša
Nobeden ne gleda
Zgodila se je napaka: %1$s
diff --git a/app/src/main/res/values-so/strings.xml b/app/src/main/res/values-so/strings.xml
index 6b4de7353..860a607f5 100644
--- a/app/src/main/res/values-so/strings.xml
+++ b/app/src/main/res/values-so/strings.xml
@@ -242,9 +242,6 @@
Dad rukuntay ma jiraan
Furo adeega, hada waxaa dooran:
- B
- K
- M
ku celi
Dhagaysi
Muuqaal
@@ -611,7 +608,6 @@
Xidh caalamadinta qoraalka
Fur caalamadinta qoraalka
Hadda waad dooran kartaa qoraalka ku dhexjira faahfaahinta. Ogow markaad caalamdinayso qoraalka boggu wuu boodboodi karaa tixraacyadana waxay noqon karaan kuwo aan lagu dhufan karin.
- %s wuxuu sheegayaa sababtan:
Akoonka waa lajoojiyay
Nidaamka dagdaga ah faahfaahin dheeraad ah uma hayo shaygan.
Akoonka soosaaraha waa la joojiyay.
diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml
index 162ba5ada..4b9c2ac36 100644
--- a/app/src/main/res/values-sq/strings.xml
+++ b/app/src/main/res/values-sq/strings.xml
@@ -295,9 +295,6 @@
Nuk ka abonues
Aktivizoje shërbimin, momentalisht e zgjedhur:
- B
- M
- k
Riprovo
Audio
Video
@@ -601,7 +598,6 @@
Zgjidhni temën tuaj të preferuar të natës - %s
Automatike (tema e pajisjes)
Radio
- %s e jep këtë arsye:
Llogaria është mbyllur
Kjo përmbajtje është private, kështu që nuk mund të luhet apo shkarkohet nga NewPipe.
Kjo përmbajtje nuk është e disponueshme në shtetin tuaj.
diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml
index 99b9e971f..02711dac2 100644
--- a/app/src/main/res/values-sr/strings.xml
+++ b/app/src/main/res/values-sr/strings.xml
@@ -78,14 +78,11 @@
Преузимања
Извештај о грешци
Програм је отказао
- Шта:\\nЗахтев:\\nЈезик садржаја:\\nЗемља садржаја:\\nЈезик апликације:\\nУслуга:\\nGMT време:\\nПакет:\\nВерзија:\\nВерзија ОС-а:
+ Шта:\\nЗахтев:\\nЈезик садржаја:\\nДржава садржаја:\\nЈезик апликације:\\nУслуга:\\nGMT време:\\nПакет:\\nВерзија:\\nВерзија ОС-а:
„reCAPTCHA“ задатак
Решите „reCAPTCHA“ задатак
Црна
Све
- хиљ.
- мил.
- млрд.
Отвори у искачућем облику
Ова дозвола је потребна за
\nотварање у искачућем режиму
@@ -117,7 +114,7 @@
О NewPipe
О нама и ЧПП
Лиценце
- Слободно и лагано стримовање на Android-у.
+ Слободно и лагано токовање на Android-у.
Погледај на GitHub-у
Прочитај лиценцу
Допринос
@@ -164,7 +161,7 @@
Без обзира имате ли идеје; превод, промене дизајна, чишћење кода или праве, озбиљне, промене кода—помоћ је увек добродошла. Што се више уради, то је боље!
Прикажите савет када притиснете позадину или искачуће дугме у видео снимку „Детаљи:“
Пусти све
- Није могуће пустити овај стрим
+ Није могуће пустити овај ток
Дошло је до непоправљиве грешке плејера
Опорављање од грешке плејера
Желите ли да избришете ову ставку из историје претраге\?
@@ -182,11 +179,11 @@
Детаљи
Подешавања аудио снимка
Није пронађен ниједан извођач довода (можете уградити ВЛЦ ради извођења садржаја).
- Преузимање фајла стрима
+ Преузимање фајла тока
Прикажи информације
Обележене плејлисте
Додај на
- Подразумевана држава за садржај
+ Подразумевана држава садржаја
Исправљање грешака
Увек
Само једном
@@ -322,7 +319,7 @@
Увоз из
Увоз
Срушите апликацију
- Изворни текстови са услуга биће видљиви у ставкама стрима
+ Изворни текстови са услуга биће видљиви у ставкама тока
Прикажи изворно време ставки
Присилно извештавање о „Rx“ изузецима који се не могу испоручити ван фрагмента или животног циклуса активности након одлагања
Пријави грешке ван животног циклуса
@@ -421,15 +418,15 @@
Врати подразумеване вредности
Желите ли да вратите подразумеване вредности\?
Није могуће прочитати сачуване картице, тако да се користе подразумеване
- Нема стримова доступних за преузимање
+ Нема токова доступних за преузимање
Дошло је до грешке: %1$s
Фајл не постоји или нема дозволе за читање или писање
Назив фајла не може бити празан
Нема таквог фајла/извора садржаја
Нема таквог фолдера
Фајл је премештен или избрисан
- Нису пронађени видео стримови
- Нису пронађени аудио стримови
+ Нису пронађени видео токови
+ Нису пронађени аудио токови
Спољни плејери не подржавају ове врсте линкова
Преузимање на спољну, SD (меморијску), картицу није могуће. Ресетовати локацију фолдера за преузимање\?
Спољна меморија није доступна
@@ -443,7 +440,7 @@
Избриши позиције репродукције
Историја гледања је избрисана
Избрисати целу историју гледања\?
- Брише историју пуштаних стримова и позиције репродукције
+ Брише историју пуштаних токова и позиције репродукције
Очисти историју гледања
Чисти колачиће које NewPipe чува када решите „reCAPTCHA“
Извоз историје, праћења, плејлисти и подешавања
@@ -495,10 +492,10 @@
Вратите последњу позицију репродукције
Настави репродукцију
Аутоматско стављање у редослед
- Наставите да завршавате (непонављајући) редослед репродукције додавањем сродног стрима
- Аутоматски стави у редослед следећи стрим
+ Наставите да завршавате (непонављајући) редослед репродукције додавањем сродног тока
+ Аутоматски стави у редослед следећи ток
Кеш метаподатака обрисан
- Искључите да бисте сакрили поља за метаподатке са додатним информацијама о креатору стрима, садржају стрима или захтеву за претрагу
+ Искључите да бисте сакрили поља за метаподатке са додатним информацијама о креатору тока, садржају тока или захтеву за претрагу
Прикажи метаподатке
Искључите да бисте сакрили опис видео снимка и додатне информације
Прикажи опис
@@ -530,10 +527,10 @@
Аутоматски (тема уређаја)
Радио
Истакнуто
- Овај садржај је доступан само корисницима који су платили, тако да га NewPipe не може стримовати или преузимати.
- Овај видео снимак је доступан само премијум YouTube Music члановима, тако да га NewPipe не може стримовати или преузимати.
- Овај садржај је приватан, тако да га NewPipe не може стримовати или преузимати.
- Ово је SoundCloud Go+ нумера, барем у вашој земљи, тако да је NewPipe не може стримовати или преузимати.
+ Овај садржај је доступан само корисницима који су платили, тако да га NewPipe не може токовати или преузимати.
+ Овај видео снимак је доступан само премијум YouTube Music члановима, тако да га NewPipe не може токовати или преузимати.
+ Овај садржај је приватан, тако да га NewPipe не може токовати или преузимати.
+ Ово је SoundCloud Go+ нумера, барем у вашој земљи, тако да је NewPipe не може токовати или преузимати.
Овај садржај није доступан у вашој земљи.
Ниједна апликација на вашем уређају не може да отвори ово
Поглавља
@@ -622,7 +619,6 @@
Омогући бирање текста унутар описа
Онемогући бирање текста унутар описа
Сада можете изабрати текст унутар описа. Имајте на уму да страница може треперети и да се на линкове можда неће моћи кликнути док сте у режиму избора.
- %s даје овај разлог:
Налог укинут
Режим брзог фида не пружа више информација о овоме.
Налог аутора је укинут.
@@ -653,7 +649,7 @@
- %s преузимања је завршено
%1$s %2$s
- Обавештења о новим стримовима
+ Обавештења о новим токовима
Обавештења
Погледај на веб-сајту
Ако имате проблема са коришћењем апликације, обавезно погледајте ове одговоре на честа питања!
@@ -666,7 +662,7 @@
Поништи трајну сличицу
Било која мрежа
Ручно проверите постоје ли нове верзије
- Спољни плејери не подржавају изабрани стрим
+ Спољни плејери не подржавају изабрани ток
Померите главни бирач картице на дно
Положај главних картица
Дошло је до грешке, погледајте обавештење
@@ -675,34 +671,34 @@
Учесталост провере
Картица
Уклонити дупликате\?
- Желите ли да уклоните све дупликате стримова на овој плејлисти\?
+ Желите ли да уклоните све дупликате токова на овој плејлисти?
Предстојеће
Подешавања ExoPlayer-а
Увек користи заобилазно решење ExoPlayer-а за подешавање површине излаза видео снимка
Изабери квалитет за спољне плејере
- Нема стримова
- Нема стримова уживо
+ Нема токова
+ Нема токова уживо
- - %s нови стрим
- - %s нова стрима
- - %s нових стримова
+ - %s нови ток
+ - %s нова тока
+ - %s нових токова
- Учитавање детаља стрима…
+ Учитавање детаља тока…
Прикажи „Сруши плејер“
- Покрени проверу нових стримова
+ Покрени проверу нових токова
Тунеловање медија је подразумевано онемогућено на вашем уређају, јер је познато да ваш уређај то не подржава.
Полутон
- Обавештавање о новим стримовима из праћења
+ Обавештавање о новим токовима из праћења
Провера ажурирања…
Избрисати све преузете фајлове са диска\?
Уклони дупликате
Прикачен коментар
ExoPlayer подразумевано
Изабери све
- Не приказују се стримови које програм за преузимање још увек не подржава
- Аудио снимак би већ требало да буде присутан у овом стриму
- Нема доступних аудио стримова за спољне плејере
- Нема доступних видео стримова за спољне плејере
+ Не приказују се токови које програм за преузимање још увек не подржава
+ Аудио снимак би већ требало да буде присутан у овом току
+ Нема доступних аудио токова за спољне плејере
+ Нема доступних видео токова за спољне плејере
Непознати формат
Непознати квалитет
Непознато
@@ -716,8 +712,8 @@
Додирните да бисте преузели %s
Провера ажурирања
Преглед сличице траке за претрагу
- Приказ следећих стримова
- Прикажи/сакриј стримове
+ Приказ следећих токова
+ Прикажи/сакриј токове
Користи резервну функцију декодера ExoPlayer-а
оригинални
Промените величину интервала учитавања на прогресивним садржајима (тренутно %s). Нижа вредност може убрзати њихово почетно учитавање
@@ -726,8 +722,8 @@
Радња покретом улево
Изаберите покрет за десну половину екрана плејера
Обавештење плејера
- Обавештења о новим стримовима за праћења
- Конфигуришите обавештење о тренутно репродукованом стриму
+ Обавештења о новим токовима за праћења
+ Конфигуришите обавештење о тренутно репродукованом току
Изаберите оригинални аудио снимак, без обзира на језик
Изаберите аудио снимак са описима за особе са оштећеним видом, ако је доступан
Преферирај описни аудио снимак
@@ -735,7 +731,7 @@
Осветљеност
Јачина звука
Ниједно
- Нови стримови
+ Нови токови
Обавештења за пријаву грешака
Увезите или извезите праћења из менија са 3 тачке
Аудио снимак
@@ -794,7 +790,7 @@
Низак квалитет
Укључи цео екран
Аватари
- Следећи стрим
+ Следећи ток
Аватари потканала
Отвори редослед пуштања
Не учитавај слике
@@ -810,7 +806,7 @@
Више опција
Сличице
Трајање
- Претходни стрим
+ Претходни ток
Дели листу URL адреса
Дели са насловима
%1$s
@@ -844,4 +840,28 @@
Изаберите групу фидова
Страница групе канала
Ликовања
+ Претрага %1$s
+ Претрага %1$s (%2$s)
+ Да бисте користили искачући плејер, изаберите %1$s у следећем менију подешавања Android-а и омогућите %2$s.
+ „Дозволи приказ преко других апликација“
+ %sк
+ %sмлн.
+ %sмлрд.
+ Избриши фајл
+ Избриши унос
+ Налог је укинут\n\n%1$s наводи овај разлог: %2$s
+ Страница SoundCloud Top 50 је уклоњена
+ SoundCloud је укинуо оригиналне топ 50 листе. Одговарајућа картица је уклоњена са ваше главне странице.
+ Уклоњен је комбиновану страницу у тренду на YouTube-у
+ YouTube је укинуо комбиновану страницу у тренду од 21. јула 2025. NewPipe је заменио подразумевану страницу у тренду са страницом уживо у тренду.\n\nТакође можете одабрати различите странице у тренду у „Подешавања > Садржај > Садржај главне странице“.
+ Игре у тренду
+ Подкасти у тренду
+ Филмови и серије у тренду
+ Музика у тренду
+ Унос избрисан
+ HTTP грешка 403 примљена са сервера током репродукције, вероватно узрокована истеком URL-а за токовање или забраном IP адресе
+ HTTP грешка %1$s примљена са сервера током репродукције
+ HTTP грешка 403 примљена са сервера током репродукције, вероватно узрокована забраном IP адресе или проблемима са деобфускацијом URL-а за токовање
+ %1$s је одбио да пружи податке, тражећи пријаву како би се потврдило да подносилац захтева није бот.\n\nВаша IP адреса је можда привремено забрањена од стране %1$s, можете сачекати неко време или прећи на другу IP адресу (на пример, укључивањем/искључивањем VPN-а или преласком са WiFi-ја на мобилне податке).
+ Овај садржај није доступан за тренутно изабрану земљу садржаја.\n\nПромените свој избор у „Подешавања > Садржај > Подразумевана држава садржаја“.
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index 3beab4181..7893eae19 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -112,9 +112,6 @@
Video
Ljud
Försök igen
- t
- mn
- md
Inga prenumeranter
- %s prenumerant
@@ -147,7 +144,7 @@
\nöppna i popup-läge
reCAPTCHA utmaning
reCAPTCHA utmaning begärd
- Hämta
+ Hämtning
Tillåtna tecken i filnamn
Ogiltiga tecken ersätts med detta värde
Ersättningstecken
@@ -169,8 +166,8 @@
Vill du ta bort det här objektet från sökhistoriken?
Huvudsidans innehåll
Tom sida
- Kiosk sida
- Kanal-sida
+ Kiosksida
+ Kanalsida
Välj en kanal
Inga kanal prenumerationer ännu
Välj en kiosk
@@ -589,7 +586,6 @@
Hämtningen har startat
Radio
Detta innehåll är endast tillgängligt för användare som har betalat för det, så det kan inte strömmas eller hämtas av NewPipe.
- %s anger detta skäl:
Kontot avslutat
Denna video är endast tillgänglig för YouTube Music Premium-medlemmar, så den kan inte strömmas eller hämtas av NewPipe.
Detta innehåll är privat, så det kan inte strömmas eller hämtas av NewPipe.
@@ -829,4 +825,29 @@
Välj en flödesgrupp
Ingen flödesgrupp har skapats ännu
Kanalgruppsida
+ Sök %1$s
+ Sök %1$s (%2$s)
+ %sK
+ %sM
+ %sB
+ Gillar
+ SoundCloud Topp 50-sida borttagen
+ SoundCloud har lagt ner de ursprungliga topp 50-listorna. Motsvarande flik har tagits bort från din startsida.
+ YouTubes kombinerade trender har tagits bort
+ YouTube har upphört med den kombinerade trendsidan från och med den 21 juli 2025. NewPipe ersatte standardtrendsidan med trendiga livestreams.\n\nDu kan också välja olika trendsidor i \"Inställningar > Innehåll > Innehåll på huvudsidan\".
+ Speltrender
+ Trendiga poddar
+ Trendiga filmer och serier
+ Trendig musik
+ För att använda Popup Player, välj %1$s i följande Android-inställningsmeny och aktivera %2$s.
+ \"Tillåt visning över andra appar\"
+ Ta bort fil
+ Ta bort post
+ Konto avslutat\n\n%1$s anger denna anledning: %2$s
+ Posten borttagen
+ HTTP-fel 403 mottogs från servern under uppspelning, troligen orsakat av att streaming-URL:en har löpt ut eller att en IP-adress har blockerats
+ HTTP-fel %1$s mottogs från servern under spelning
+ HTTP-fel 403 mottogs från servern under spelning, troligen orsakat av en IP-avstängning eller problem med deobfuskering av streaming-URL:er
+ %1$s vägrade att tillhandahålla data och bad om en inloggning för att bekräfta att den som begärde detta inte är en bot.\n\nDin IP-adress kan ha blivit tillfälligt avstängd av %1$s. Du kan vänta en stund eller byta till en annan IP-adress (till exempel genom att slå på/av ett VPN eller genom att byta från WiFi till mobildata).
+ Detta innehåll är inte tillgängligt för det valda innehållslandet.\n\nÄndra ditt val från \"Inställningar > Innehåll > Standardinnehållsland\".
diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml
index 906249376..f1d388393 100644
--- a/app/src/main/res/values-ta/strings.xml
+++ b/app/src/main/res/values-ta/strings.xml
@@ -245,7 +245,6 @@
உம் அபிமான பியர்டியூப் நிகழ்வுகளைத் தேர்ந்தெடு
உள்ளடக்க இயல்பிருப்பு மொழி
இயக்குதலைத் மறுதொடர்
- நி
நிகழ்வு ஏற்கனவே உள்ளது
யூடியூபின் \"கட்டுப்பாடு பயன்முறை\"ஐ இயக்கு
பாடல்கள்
@@ -260,8 +259,6 @@
என்ன:\\nகோரிக்கை:\\nஉள்ளடக்க மொழி:\\nஉள்ளடக்க நாடு:\\nசெயலி மொழி:\\nசேவை:\\nGMT நேரம்:\\nசிப்பம்:\\nபதிப்பு:\\nOS பதிப்பு:
காணொளியை இயக்கு, காலவளவு:
கருத்தளிப்புகள்
- ஆ
- ப.ல
இயக்கியைச் சிதை
பட்டியல்களில் இயக்கக குறியட நிலைகாட்டிகளைக் காட்டு
துணையியக்கியில் காணொளிகளை துவக்காதே, ஆனால் தானாக சுழற்றல் பூட்டப்பட்டிருந்தால் நேரடியாக முழுதிரைக்குத் திரும்பு. முழுதிரையை வெளியேறி நீங்கள் இன்னும் துணையியக்கியை அணுகலாம்
@@ -431,7 +428,6 @@
பதிவிறக்க வரிசையை கட்டுப்படுத்துங்கள்
ஒரு பதிவிறக்கம் ஒரே நேரத்தில் இயங்கும்
உங்கள் சாதனத்தில் எந்த பயன்பாடும் இதைத் திறக்க முடியாது
- %s இந்த காரணத்தை வழங்குகிறது:
துணை சேனல் அவதாரங்கள்
அவதாரங்கள்
எக்சோப்ளேயர் இயல்புநிலை
diff --git a/app/src/main/res/values-te/strings.xml b/app/src/main/res/values-te/strings.xml
index c537495ba..b95e04c0c 100644
--- a/app/src/main/res/values-te/strings.xml
+++ b/app/src/main/res/values-te/strings.xml
@@ -77,9 +77,6 @@
వీడియో
ఆడియో
మళ్ళీ ప్రయత్నించు
- కి
- ఎం
- బిలియన్
సభ్యులు లేరు
- %s సభ్యుడు
diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml
index bcbbca0a4..01be8d1d2 100644
--- a/app/src/main/res/values-th/strings.xml
+++ b/app/src/main/res/values-th/strings.xml
@@ -165,9 +165,6 @@
วิดีโอ
เสียง
ลองอีกครั้ง
- พัน
- ล้าน
- พันล้าน
ไม่มีสมาชิกที่สมัครรับ
- %s บอกรับ
@@ -412,4 +409,23 @@
ไม่มี
ไม่
ใช่/ตกลง
+ วิดีโอ
+ ปิดเสียง
+ เลิกปิดเสียง
+ ใหม่
+ ฟีด
+ เพลง
+ อัลบั้ม
+ ไม่ต้อง
+ ล่าสุด
+ ความคิดเห็น
+ คำอธิบาย
+ แนะนำ
+ หมวดหมู่
+ แท็ก
+ ลิขสิทธิ์
+ ภาษา
+ จัดเรียง
+ การ์ด
+ กำลังจะมา
diff --git a/app/src/main/res/values-ti/strings.xml b/app/src/main/res/values-ti/strings.xml
index f25b86cc1..ccce73524 100644
--- a/app/src/main/res/values-ti/strings.xml
+++ b/app/src/main/res/values-ti/strings.xml
@@ -52,7 +52,7 @@
ቀዳማይ ወሰን ተጠዋቃ
ደገመ
ድምጺ ምውራድ ማህደር
- ቦኦክማርከድ ዝርዝር-ጸወታ
+ ዝርዝር-ጸወታት
ናይ ድምጺ ፋይል ኣራግፍ ምረጽ
ዝጎደለ ኮረ ኣፕፕ ኣውራድ፧
ነባሪ ቅርጺ ድምጺ
@@ -94,4 +94,95 @@
ደርፍታት
ኣልበማት
ስነ-ጥበባውያን
+ %1$s ድለ
+ ድለ %1$sን %2$s
+ ዝርዝር-ጸወታት
+ ራብዓይ ስጉምቲ መጠወቒ
+ ሕንፍሽፍሽ
+ ታሪኽ
+ ዞባዊ
+ ኣኼባ
+ ኣወግድ
+ ዝርዝር ሓበሬታ
+ መስርዕ
+ ተሰሪዑ
+ ስም ቀያር
+ ስም
+ ዓባስ
+ ኣብ ዝርዝር-ጸወታ ኮነ
+ ግጡም
+ ሙሉእ
+ ስጉሚ
+ ተቐበል
+ ንጸግ
+ ዋላ-ሓደ
+ ብፍጹም
+ ዝርዝር
+ ብዘይ መግለጺ ጽሑፍ
+
+ - %s ተራእዩ
+ - %s ተራእዩ
+
+
+ - %s ተኸታሊ
+ - %s ተኸታተልቲ
+
+ ሓድሽ ዝርዝር ጸወታ
+ ፍጠር
+
+ - %d ሰዓት
+ - %d ሰዓታት
+
+
+ - %d መዓልቲ
+ - %d መዓልታት
+
+
+ - %d ካልኢት
+ - %d ካልኢት
+
+
+ - %d ደቒቕ
+ - %d ደቓይቕ
+
+ እንታይ ሓድሽ ኣሎ
+ ሓድሽ
+ ጉጅለታት መስመር
+ ኩሉ ተጻወቶ
+ ኣብ ዝመጺእ
+ ብኸፊል ዝተራእየ
+ ብምሉእ ዝተራእየ
+ እዞም ዝስዕቡ ውሕጅታት ኣርእዩ
+ ዝተሓደሰ ዕለት: %s
+ ቅልጡፍ ኣገባብ ኣንቅሕ
+ ዝርዝራት:
+ ፈተውቲ
+ ጸላእቲ
+ ርእይቶታት
+ መብርሂ
+ ብድምጺ
+ እንደገና ፈትን
+ %sሽ
+ %sሚ
+ %sቢ
+ ጀምር
+ ደምስስ
+ ሰሩዞ
+ ስም ቀያር
+ ስሕተት
+ መፍለዪ
+ ህዝባዊ
+ ብሕትነት
+ ፍቓድታት
+ ፍቓድ ኣንብብ
+ ምድብ
+ ፍቓድ
+ እዋናዊታት
+ ኣቫታራት
+ ባነራት
+ ዘይተዘርዘረ
+ ብሕታዊ
+ ውሽጣዊ
+ ተኸታተልቲ
+ መርበብ-ቦታ ክፈት
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index e2774ad39..947d0bcf9 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -88,9 +88,6 @@
Devre dışı
Yorumunuz (İngilizce):
Ayrıntılar:
- b
- M
- M
Bu izin, açılır pencere kipinde
\naçmak için gereklidir
reCAPTCHA formu
@@ -611,7 +608,6 @@
Açıklamadaki metni seçmeyi etkinleştir
Artık, açıklamadaki metni seçebilirsiniz. Seçim kipindeyken sayfanın titreyebileceğini ve bağlantıların tıklanamayacağını unutmayın.
Web sitesini aç
- %s şu nedeni sağlıyor:
Hesap sonlandırıldı
Hızlı besleme kipi bununla ilgili daha çok bilgi sağlamıyor.
Yazarın hesabı sonlandırılmış.
@@ -834,4 +830,24 @@
%1$s İle Ara (%2$s)
SoundCloud Top 50 sayfası kaldırıldı
SoundCloud, özgün Top 50 listesini artık yayınlamıyor. İlgili sekme ana sayfanızdan kaldırıldı.
+ %sK
+ %sM
+ %sB
+ YouTube birleşik trendler kaldırıldı
+ YouTube, 21 Temmuz 2025\'ten sonra birleşik trendler sayfasını kaldırdı. NewPipe, öntanımlı trendler sayfasını trend canlı akışlarla değiştirdi.\n\n\"Ayarlar > İçerik > Ana sayfanın içeriği\"nden başka trend sayfalar seçebilirsiniz.
+ Oyun trendleri
+ Trend podcastler
+ Trend film ve gösteriler
+ Trend müzik
+ Açılır Oynatıcıyı kullanmak için Android ayarlar menüsünden %1$s seçilmeli ve %2$s etkinleştirilmeli.
+ “Diğer uygulamaların üstünde göstermeye izin ver”
+ Dosyayı sil
+ Girdiyi sil
+ Girdi silindi
+ Hesap sonlandırıldı\n\n%1$s şu nedeni sağladı: %2$s
+ Oynatırken sunucudan HTTP 403 hatası alındı, akış URL’si bitmiş ya da IP engellenmiş olabilir
+ Oynatırken sunucudan HTTP %1$s hatası alındı
+ Oynatırken sunucudan HTTP 403 hatası alındı, IP engeli ya da akış URL’si çözme sorunları olabilir
+ %1$s veri sağlamayı geri çevirdi, istekçinin robot olmadığını doğrulaması için oturum açmasını istiyor.\n\n%1$s, IP adresinizi geçici olarak engellemiş olabilir, bir süre bekleyebilir ya da başka IP\'ye geçebilirsiniz (örneğin VPN\'i açıp/kapatarak ya da WiFi\'den mobil veriye geçerek).
+ Bu içerik şu anda seçili içerik ülkesinde kullanılamıyor.\n\nSeçiminizi \"Ayarlar > İçerik > Öntanımlı içerik ülkesi\"nden değiştirin.
diff --git a/app/src/main/res/values-tzm/strings.xml b/app/src/main/res/values-tzm/strings.xml
index 8ef077a9f..a62b37fa3 100644
--- a/app/src/main/res/values-tzm/strings.xml
+++ b/app/src/main/res/values-tzm/strings.xml
@@ -113,7 +113,6 @@
Kkes
Senulfu
Senti
- ifḍ
Als-arem
Imesli
Avidyu
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index d548dac3c..58e62c0d8 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -65,9 +65,6 @@
Відео
Аудіо
Повторити спробу
- тис
- млн
- млрд
Почати
Пауза
Видалити
@@ -627,7 +624,6 @@
Заборонити виділення тексту в описі
Дозволити виділяти текст в описі
Тепер можна виділяти текст в описі. Зауважте, що сторінка може мигати і посилання можуть не працювати в режимі виділення.
- %s подає таку причину:
Неможливо завантажити стрічку для «%s».
Помилка завантаження стрічки
Обліковий запис автора припинено.
@@ -853,4 +849,24 @@
Пошук %1$s (%2$s)
Сторінку SoundCloud Top 50 видалено
SoundCloud припинив підтримку оригінальних чартів Топ-50. Відповідну вкладку видалено з вашої головної сторінки.
+ Видалено об’єднаний тренд YouTube
+ YouTube припинив підтримку об’єднаної сторінки трендів з 21 липня 2025 року. NewPipe замінив стандартну сторінку трендів на сторінку трендових прямих трансляцій.\n\nВи також можете вибрати різні сторінки трендів у розділі «Налаштування» > «Контент» > «Контент головної сторінки».
+ Ігрові тренди
+ Популярні подкасти
+ Популярні фільми та шоу
+ Популярна музика
+ %sтис
+ %sмлн
+ %sмлрд
+ Щоб використовувати спливаючий програвач, виберіть %1$s у наступному меню налаштувань Android та увімкніть %2$s.
+ “Дозволити показ поверх інших програм”
+ Видалити файл
+ Видалити запис
+ Запис видалено
+ Обліковий запис заблоковано\n\n%1$s вказує таку причину: %2$s
+ Під час відтворення від сервера отримано помилку HTTP 403, ймовірно, через закінчення терміну дії URL-адреси потокової передачі або заборону IP-адреси
+ Помилка HTTP %1$s отримана від сервера під час відтворення
+ Під час відтворення від сервера отримано помилку HTTP 403, ймовірно, через заборону IP-адреси або проблеми з деобфускацією URL-адреси потокової передачі
+ %1$s відмовився надати дані, запитуючи логін для підтвердження того, що запитувач не є ботом.\n\nВаша IP-адреса могла бути тимчасово заблокована %1$s. Ви можете почекати деякий час або перейти на іншу IP-адресу (наприклад, увімкнувши/вимкнувши VPN або переключившись з Wi-Fi на мобільні дані).
+ Цей контент недоступний для вибраної країни контенту.\n\nЗмініть свій вибір у розділі \"Налаштування > Контент > Країна контенту за замовчуванням\".
diff --git a/app/src/main/res/values-und/strings.xml b/app/src/main/res/values-und/strings.xml
index 94e4f9dd6..0bd3bf442 100644
--- a/app/src/main/res/values-und/strings.xml
+++ b/app/src/main/res/values-und/strings.xml
@@ -70,7 +70,6 @@
ویڈیو
آڈیو
فیر کرو
- ہزار
بݨاؤ
بارے
لائیسنس
diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml
index 1a434ab63..bb95e2811 100644
--- a/app/src/main/res/values-ur/strings.xml
+++ b/app/src/main/res/values-ur/strings.xml
@@ -146,9 +146,6 @@
ویڈیو
آڈیو
دوبارہ کوشش کریں
- ہزار
- دہ لاکھ
- ارب
کوئی صارفین نہیں
- %s صارف
diff --git a/app/src/main/res/values-v35/styles.xml b/app/src/main/res/values-v35/styles.xml
new file mode 100644
index 000000000..beb16bcdf
--- /dev/null
+++ b/app/src/main/res/values-v35/styles.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml
index e1073e7af..29dcb8c4d 100644
--- a/app/src/main/res/values-vi/strings.xml
+++ b/app/src/main/res/values-vi/strings.xml
@@ -6,7 +6,7 @@
Cài đặt
Hủy
Mở trong trình duyệt
- Mở trong chế độ bật lên
+ Mở trong cửa sổ bật lên
Chia sẻ
Tải xuống
Tìm kiếm
@@ -82,9 +82,6 @@
Video
Âm thanh
Thử lại
- nghìn
- triệu
- tỉ
Bắt đầu
Dừng
Xóa
@@ -123,7 +120,7 @@
Đã hủy đăng ký kênh
Không thể thay đổi tình trạng đăng ký
Không thể cập nhật tình trạng đăng ký
- Không tìm thấy trình phát trực tuyến nào (bạn có thể cài đặt VLC để phát nó).
+ Không tìm thấy trình phát trực tuyến nào (bạn có thể cài đặt VLC để phát).
Tải tệp luồng về
Hiện thông tin
Kênh đăng ký
@@ -605,7 +602,6 @@
Tắt chọn văn bản trong mô tả
Bật chọn văn bản trong mô tả
Bây giờ bạn có thể chọn văn bản trong mô tả. Lưu ý rằng trang có thể nhấp nháy và các liên kết có thể không nhấn vào được trong khi ở chế độ chọn.
- %s cung cấp lý do này:
Tài khoản đã bị chấm dứt
Chế độ nạp nhanh không cung cấp thêm thông tin về điều này.
Tài khoản của tác giả đã bị chấm dứt.
@@ -809,4 +805,24 @@
\nBạn có muốn kích hoạt tính năng này không?
Có
Cài đặt trong xuất đang được nhập sử dụng định dạng dễ bị tấn công và không được dùng nữa kể từ NewPipe 0.27.0. Đảm bảo rằng bản xuất đang được nhập là từ một nguồn đáng tin cậy và chỉ ưu tiên sử dụng các bản xuất lấy từ NewPipe 0.27.0 hoặc mới hơn trong tương lai. Hỗ trợ nhập cài đặt ở định dạng dễ bị tấn công này sẽ sớm bị xóa hoàn toàn và khi đó các phiên bản cũ của NewPipe sẽ không thể nhập cài đặt xuất từ phiên bản mới nữa.
+ Tìm kiếm %1$s
+ Tìm kiếm %1$s (%2$s)
+ Danh sách phát
+ %sN
+ %sTr
+ %sTỷ
+ Chọn một nhóm nguồn cấp dữ liệu
+ Chưa có nhóm nguồn cấp dữ liệu nào được tạo
+ Trang nhóm kênh
+ phụ
+ Thích
+ Chia sẻ dưới dạng danh sách phát tạm thời của YouTube
+ SoundCloud 50 trang hàng đầu đã xóa
+ SoundCloud đã ngừng hiển thị bảng xếp hạng Top 50 ban đầu. Tab tương ứng đã bị xóa khỏi trang chính của bạn.
+ Đã xóa kết hợp đang thịnh hành của YouTube
+ YouTube đã ngừng cung cấp trang thịnh hành kết hợp kể từ ngày 21 tháng 7 năm 2025. NewPipe đã thay thế trang xu hướng mặc định bằng các buổi phát trực tiếp theo thịnh hành.\n\nBạn cũng có thể chọn các trang thịnh hành khác nhau trong \"Cài đặt > Nội dung > Nội dung của trang chính\".
+ Trò chơi thịnh hành
+ Podcasts đang thịnh hành
+ Phim và chương trình đang thịnh hành
+ Âm nhạc đang thịnh hành
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index c63e952f0..0a8c8a944 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -71,8 +71,6 @@
- %s 次观看
- 千
- 百万
开始
暂停
删除
@@ -153,7 +151,6 @@
详细信息:
播放视频,时长:
视频上传者的头像缩略图
- 十亿
NewPipe 正在下载
请稍后在设置中设定下载目录
使用悬浮窗模式
@@ -602,7 +599,6 @@
启用简介中的文本选择功能
你现在可以选择简介中的文本,注意,在选择模式下,页面可能会闪烁,链接可能无法点击。
打开网站
- %s 提供这个原因:
账号被终止
快速 Feed 模式不提供关于这个的更多信息。
作者账号已被终止。
@@ -820,4 +816,24 @@
搜索 %1$s (%2$s)
移除了 SoundCloud Top 50 页面
SoundCloud 已停止发布原创 Top 50 榜单。相应的标签页已从你的主页移除。
+ 移除了 Youtube 合并的“时下流行”标签页
+ 自 2025.7.21 起, Youtube 下线了合并的“时下流行”标签页。Newpipe 用“时下流行”的直播替代了默认的“时下流行”页。\n\n你也可以在 “设置 > 内容> 主页内容”中选择不同的“时下流行”页。
+ “时下流行”的游戏视频
+ “时下流行”的播客
+ “时下流行”的电影和娱乐节目
+ “时下流行”的音乐
+ %s千
+ %s百万
+ %s十亿
+ 要使用弹窗播放器,请在接下来的安卓设置中选择 %1$s 并开启 %2$s。
+ “允许显示在其他应用上方”
+ 删除文件
+ 删除条目
+ 删除了条目
+ 账户终止\n\n%1$s 提供了这个原因:%2$s
+ 播放时从服务器收到 HTTP 403 错误,可能因串流 URL 过期或 IP 封锁导致
+ 播放时从服务器收到 HTTP %1$s 错误
+ 播放时从服务器收到 HTTP 403 错误,可能因 IP 封锁或串流 URL 解密问题导致
+ %1$s 拒绝提供数据, 要求登录确认请求方不是机器人。\n\n你的 IP 可能已经暂时被 %1$s 封禁,你可以等待一段时间或切换到不同 IP (比如开/关 VPN, 或者从 WiFi 连接切换到移动数据)。
+ 此内容对当前选中的内容地区不可用。\n\n要更改选择,请前往 “设置 > 内容 > 默认内容地区”。
diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml
index 6b5529992..24f457c25 100644
--- a/app/src/main/res/values-zh-rHK/strings.xml
+++ b/app/src/main/res/values-zh-rHK/strings.xml
@@ -87,8 +87,6 @@
全部嘢
App/界面閃退
經過:\\n請求:\\n內容語言:\\n內容國家:\\nApp 語言:\\n服務:\\nGMT 時間:\\n封裝:\\n版本:\\nOS 版本:
- 千
- 百萬
reCAPTCHA 考驗
以浮面模式開啟
\n有呢個權限至得
@@ -103,7 +101,6 @@
不適用
抹走
最佳解像度
- 十億
關於 NewPipe
第三方版權協議
© %1$s %2$s 版權所有,根據 %3$s 嘅條款授權
@@ -489,7 +486,6 @@
NewPipe 仲未支援到呢樣。
\n
\n希望未來會喺日後嘅版本支援啦。
- %s 話理由如下:
搵唔到合適嘅檔案總管進行呢個動作。
\n請安裝一個檔案管理程式,又或者試下喺下載設定度停用「%s」
搵唔到合適嘅檔案總管進行呢個動作。
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 1427ce483..2ceb296b0 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -1,7 +1,7 @@
發佈於 %1$s
- 未找到串流播放器。安裝 VLC?
+ 找不到串流播放器。是否安裝 VLC?
安裝
取消
以瀏覽器開啟
@@ -14,14 +14,14 @@
使用外部影片播放器
使用外部音訊播放器
影片下載資料夾
- 下載好的影片檔案會儲存在這裡
+ 下載完的影片檔案會儲存在這裡
選擇視訊檔案的下載資料夾
預設解析度
- 用 Kodi 播放
- 顯示用 Kodi 媒體中心播放影片的選項
+ 使用 Kodi 播放
+ 顯示使用 Kodi 媒體中心播放影片的選項
聲音
要安裝缺少的 Kore 應用程式嗎?
- 顯示「用 Kodi 播放」的選項
+ 顯示「使用 Kodi 播放」的選項
預設音訊格式
主題
深色
@@ -40,8 +40,8 @@
不喜歡
音訊下載資料夾
下載好的音訊檔案會儲存在這裡
- 選擇音訊檔的下載資料夾
- 點選放大鏡即可開始。
+ 選擇音訊檔案的下載資料夾
+ 輕觸放大鏡即可開始。
以懸浮視窗開啟
移除某些解析度的音訊
背景播放
@@ -77,14 +77,11 @@
資訊:
發生了什麼事:
發生了什麼:\\n請求:\\n內容語言:\\n內容國家:\\n應用程式語言:\\n服務:\\nGMT 時間:\\n套件:\\n版本:\\n系統版本:
- 您的留言(請用英語):
+ 您的留言 (請用英語):
詳細資訊:
影片
音訊
重試
- 千
- 百萬
- 十億
開始
暫停
刪除
@@ -114,9 +111,9 @@
搜尋記錄
在本機儲存搜尋記錄
觀看記錄
- 記錄觀看過的影片
+ 記錄已觀看的影片
恢復播放
- 在干擾結束後繼續播放(例如有來電)
+ 在干擾結束後繼續播放 (例如有來電)
播放器
行為
歷史記錄與快取
@@ -136,8 +133,8 @@
沒有影片
下載
檔案名稱中允許的字元
- 不符合設定的字元將會被替換為此字串
- 替換為
+ 無效字元將會被替換為此值
+ 替換字元
字母與數字
大部分的特殊字元
關於 NewPipe
@@ -148,13 +145,13 @@
Android 上自由且輕巧的串流播放器。
在 GitHub 上檢視
NewPipe 使用的授權條款
- 不管你有什麼點子──翻譯、設計、程式碼整理,或者程式碼撰寫──我們永遠歡迎你來幫忙。完成的越多,NewPipe 也會更好!
+ 不管您有什麼點子 ── 翻譯、設計、清理或撰寫大量程式碼 ── 我們永遠歡迎您來幫忙。做得越多,NewPipe 就會更好!
閱讀授權條款
貢獻
歷史記錄
歷史記錄
確定要刪除此項搜尋記錄嗎?
- 找不到串流播放器(您可以安裝 VLC 來播放)。
+ 找不到串流播放器 (您可以安裝 VLC 來播放)。
顯示「長按以新增」提示
預設內容國家
全部播放
@@ -175,7 +172,7 @@
網站
匯入資料庫
匯出資料庫
- 覆蓋您目前的歷史記錄、訂閱與設定(選用)
+ 覆寫您目前的歷史記錄、訂閱與設定 (選用)
匯出歷史記錄、訂閱內容、播放清單、設定
回饋
如欲了解更多有關 NewPipe 的資訊和新聞,請造訪我們的網站。
@@ -210,7 +207,7 @@
正在載入要求的內容
下載串流檔案
顯示資訊
- 書籤播放列表
+ 書籤播放清單
新增至
拖曳以重新排序
建立
@@ -241,8 +238,8 @@
強制報告在處理完片段或活動週期外發生的無法傳遞的 Rx 異常
使用粗略但快速的尋找
粗略的尋找能讓播放器以降低的精確度更快找到影片的進度位置。尋找 5、15 或 25 秒無法與其一同使用
- 自動排序下一個串流
- 透過加入相關的串流來繼續結束的(未重複)播放佇列
+ 自動佇列至下一個串流
+ 透過加入相關的串流來繼續結束的 (未重複) 播放佇列
檔案
無效的資料夾
無效的檔案或內容來源
@@ -257,17 +254,9 @@
無法匯入訂閱內容
無法匯出訂閱內容
之前的匯出
- 檔案不存在或讀取或寫入權限不足
- 從 Google Takeout 匯入您的 YouTube 訂閱:
-\n
-\n1. 移至此網址:%1$s
-\n2. 當被提示時登入帳號
-\n3. 按一下「包含所有資料」,接著「取消選取全部」,然後僅勾選「訂閱」並按一下「確定」
-\n4. 按一下「下一步」然後「建立匯出」
-\n5. 在「下載」按鈕出現後按一下它
-\n6. 點擊下方的「匯入檔案」並選取已下載的 zip 檔案
-\n7. [若 zip 匯入失敗] 擷取 .csv 檔案(通常位於「YouTube 與 YouTube Music/訂閱/訂閱.csv」),按一下下方的「匯入檔案」並選取擷取的 csv 檔案
- yourID, soundcloud.com/yourid
+ 檔案不存在或缺少讀寫檔案的權限
+ 從 Google Takeout 匯入您的 YouTube 訂閱: \n \n1. 移至此網址:%1$s \n2. 當被提示時登入帳號 \n3. 按一下「包含所有資料」,接著「取消選取全部」,然後僅勾選「訂閱」並按一下「確定」 \n4. 按一下「下一步」然後「建立匯出」 \n5. 在「下載」按鈕出現後按一下它 \n6. 點擊下方的「匯入檔案」並選取已下載的 zip 檔案 \n7. [若 zip 匯入失敗] 擷取 .csv 檔案 (通常位於「YouTube 與 YouTube Music/訂閱/訂閱.csv」),按一下下方的「匯入檔案」並選取擷取的 csv 檔案
+ 您的 ID, soundcloud.com/yourid
請記住,此操作可造成昂貴網路花費。
\n
\n您是否希望繼續?
@@ -278,13 +267,13 @@
\n3. 當被提示時登入帳號
\n4. 複製您被重新導向到的個人設定檔網址。
已清除圖片快取
- 清除已快取的後設資料
+ 清除已快取的詮釋資料
移除所有已快取的網頁資料
- 已清除後設資料快取
+ 已清除詮釋資料快取
播放速度控制
節奏
音高
- 解除掛鉤(可能導致失真)
+ 解除掛鉤 (可能導致失真)
偏好的「開啟」動作
開啟內容時的預設動作 ─ %s
沒有可供下載的串流
@@ -353,7 +342,7 @@
下載失敗
生成獨特的名稱
覆寫
- 已有此名稱的已下載檔案
+ 有已下載的同名檔案
已有進行中的下載與此同名
顯示錯誤
無法建立檔案
@@ -369,7 +358,7 @@
最大重試次數
在取消下載前的最大嘗試數
在計量收費網路上時中斷
- 在切換到行動數據時很有用(雖然某些下載無法暫停)
+ 切換到行動數據時很有用,雖然某些下載無法暫停
事件
會議
連線已逾時
@@ -385,8 +374,8 @@
在清單中顯示播放位置指示器
清除資料
播放位置已刪除
- 檔案已遭移動或刪除
- 與此同名的檔案已存在
+ 檔案已被移動或刪除
+ 同名的檔案已存在
無法覆寫檔案
已有擱置中的下載與此同名
NewPipe 在處理檔案時被關閉
@@ -419,21 +408,21 @@
- %s 位聽眾
快轉/快退搜尋持續時間
- PeerTube 站臺
- 選取您最愛的 PeerTube 站臺
- 在 %s 上找到您喜愛的站臺
- 新增站臺
- 輸入站臺網址
- 無法驗證站臺
+ PeerTube 實例
+ 選取您最愛的 PeerTube 實例
+ 在 %s 上找到您喜歡的實例
+ 新增實例
+ 輸入實例網址
+ 無法驗證實例
僅支援 HTTPS 網址
- 站臺已存在
+ 實例已存在
本機
最近新增
最喜歡
- 自動生成(未找到上傳者)
+ 自動生成 (未找到上傳者)
正在恢復
無法恢復此下載
- 選擇一個站臺
+ 選擇一個實例
清除下載歷史記錄
刪除已下載的檔案
給予顯示在其他應用程式上層的權限
@@ -475,20 +464,10 @@
上次更新後,訂閱被視為過時的時間 ─ %s
總是更新
在可用時從專用 feed 擷取
- 其在某些服務中可用,且通常較快速,但可能只會回傳有限的項目,而且資訊通常不完整(例如:沒有持續時間、項目類型、沒有即時狀態)
+ 其在某些服務中可用,且通常較快速,但可能只會回傳有限的項目,而且資訊通常不完整 (例如:沒有持續時間、項目類型、沒有即時狀態)
啟用快速模式
停用快速模式
- 您覺得 feed 載入太慢了嗎?如果是的話,試著啟用快速載入(您可以在設定中變更或按下下方的按鈕)。
-\n
-\nNewPipe 提供兩個 feed 載入策略:
-\n• 擷取整個訂閱頻道,慢但是完整。
-\n• 使用專用的伺服器端點,較快速但是通常不完整。
-\n
-\n兩者之間的差別是,較快速的通常缺少部份資訊,如項目的持續時間或類型(無法區分直播影片或一般影片),而且其可能會回傳較少項目。
-\n
-\nYouTube 是一種透過其 RSS feed 提供這種快速方式的例子。
-\n
-\n因此,請選取您較偏好的:速度或準確的資訊。
+ 您覺得 feed 載入太慢了嗎?如果是的話,試著啟用快速載入 (您可以在設定中變更或按下下方的按鈕)。 \n \nNewPipe 提供兩個 feed 載入策略: \n• 擷取整個訂閱頻道,慢但是完整。 \n• 使用專用的伺服器端點,較快速但是通常不完整。 \n \n兩者之間的差別是,較快速的通常缺少部份資訊,如項目的持續時間或類型(無法區分直播影片或一般影片),而且其可能會回傳較少項目。 \n \nYouTube 是一種透過其 RSS feed 提供這種快速方式的例子。 \n \n因此,請選取您較偏好的:速度或準確的資訊。
NewPipe 尚未支援此內容。
\n
\n希望它會在未來的版本中支援。
@@ -501,10 +480,9 @@
\n
\n如果您想要觀看,請在設定中開啟「%1$s」。
是的,包括已部份觀看的影片
- 在新增到播放清單前和後已觀看的影片將被移除。
-\n您確定嗎?此動作無法復原!
+ 已觀看過的影片在加入播放清單後將被移除。\n您確定嗎?此動作無法復原!
移除已觀看的影片?
- 移除已觀看
+ 移除已觀看的影片
來自服務的原始文字將在串流項目中可見
在項目上顯示原始時間
開啟 YouTube 的「嚴格篩選模式」
@@ -533,7 +511,7 @@
隨機
循環
您可以選取最多三個動作來顯示在簡潔通知中!
- 透過輕觸下方的通知來編輯它。使用右側的勾選框,最多可以選取三個在簡潔通知中顯示。
+ 透過輕觸下方的通知動作來編輯它們。使用右側的勾選框,最多可以選取三個在簡潔通知中顯示。
第五動作按鈕
第四動作按鈕
第三動作按鈕
@@ -548,8 +526,8 @@
reCAPTCHA cookies 已被清除
清除 reCAPTCHA cookies
YouTube 有提供「嚴格篩選模式」,可以隱藏潛在的成人內容
- 顯示可能不適於兒童的內容,因為其有年齡限制(如 18 歲以上等)
- 讓 Android 根據縮圖中的主要色彩來自訂通知的顏色(請注意,此功能不是在所有裝置上都能正常運作)
+ 顯示可能不適於兒童的內容,因為其有年齡限制 (例如 18 歲以上)
+ 讓 Android 根據縮圖中的主要色彩來自訂通知的顏色 (請注意,此功能並不是在所有裝置上都能正常運作)
彩色通知
於鎖定畫面背景與通知使用縮圖
顯示縮圖
@@ -581,7 +559,7 @@
下載已經開始
您可以在下方選取您最愛的夜間佈景主題
選取您最愛的夜間佈景主題 ─ %s
- 自動(裝置佈景主題)
+ 自動 (裝置佈景主題)
深色主題
顯示頻道詳細資訊
如果您遇到黑畫面或影片播放停頓的現象,請停用媒體隧道。
@@ -602,7 +580,6 @@
啟用選取描述中的文字
您現在可以選取描述中的文字了。請注意,在選取模式下,頁面可能會閃爍,連結也可能無法點擊。
開啟網站
- %s 提供了這個理由:
帳號已終止
快速 feed 模式不會提供更多資訊。
作者的帳號已被終止。
@@ -618,11 +595,11 @@
平板電腦模式
留言已停用
不要顯示
- 低品質(較小)
- 高品質(較大)
+ 低品質 (較小)
+ 高品質 (較大)
拖動列縮圖預覽
被創作者加心號
- 標記為已看
+ 標記為已觀看
在圖片頂部顯示畢卡索彩色絲帶,指示其來源:紅色代表網路、藍色代表磁碟、綠色代表記憶體
顯示圖片指示器
遠端搜尋建議
@@ -650,11 +627,9 @@
回報錯誤的通知
顯示錯誤 SnackBar
建立錯誤通知
- 找不到適合此動作的檔案管理程式。
-\n請安裝相容於儲存空間存取框架的檔案管理員
- 找不到適合此動作的檔案管理程式。
-\n請安裝檔案管理程式或在下載設定嘗試停用「%s」
- NewPipe 遇到錯誤,點擊以回報
+ 找不到適合此動作的檔案管理員。 \n請安裝相容於儲存空間存取框架的檔案管理員
+ 找不到適合此動作的檔案管理員。 \n請安裝檔案管理員或在下載設定裡嘗試停用「%s」
+ NewPipe 遭遇了一個錯誤,輕觸以回報
發生錯誤,請查看通知
釘選的留言
LeakCanary 無法使用
@@ -695,7 +670,7 @@
排序
若您在使用此應用程式時遇到任何問題,請務必先看看常見問題的答案!
您正在執行最新版本的 NewPipe
- 輕點以下載 %s
+ 輕觸以下載 %s
快速模式
從三點式選單匯入或匯出訂閱
此選項僅在主題選擇為 %s 時可用
@@ -709,7 +684,7 @@
移除重複的?
顯示以下串流
顯示/隱藏串流
- 完全觀看
+ 完全看完
部份觀看
即將到來
移除重複的
@@ -733,7 +708,7 @@
原始
配音
描述性
- 變更漸進式內容的載入間隔大小(目前為 %s)。較低的值可能會加速初始載入速度
+ 變更漸進式內容的載入間隔大小 (目前為 %s)。較低的值可能會加速初始載入速度
偏好描述性的音訊
若可用,為視障人士選取帶有描述的音訊軌道
無論語言都選取原始音訊軌道
@@ -753,7 +728,7 @@
頻道頁面上顯示哪些分頁
頻道分頁
短片
- 正在載入後設資料……
+ 正在載入詮釋資料……
擷取頻道分頁
關於
專輯
@@ -796,7 +771,7 @@
顯示更多
顯示較少
- 透過點擊下面的每個通知操作來編輯它。前三個動作(播放/暫停、上一個與下一個)由系統設定,無法自訂。
+ 透過輕觸下方的通知動作來編輯它們。前三個動作 (播放/暫停、上一個與下一個) 由系統設定,無法自訂。
裝置上沒有足夠的空間
備份與還原
重設設定
@@ -820,4 +795,24 @@
搜尋 %1$s (%2$s)
已移除 SoundCloud Top 50 頁面
SoundCloud 已停止原有的 Top 50 排行榜。對應的標籤已從您的首頁移除。
+ %sK
+ %sM
+ %sB
+ 已移除 YouTube 合併熱門
+ YouTube 自2025年7月21日起停止使用合併熱門頁面。NewPipe 用熱門直播取代預設熱門頁面。\n\n您也可以在「設定」→「內容」→「首頁內容」中選擇不同的熱門頁面。
+ 遊戲熱門
+ 熱門 podcast
+ 熱門電影與節目
+ 熱門音樂
+ 若要使用彈出式播放器,請在以下 Android 設定選單中選取 %1$s,並啟用 %2$s。
+ 「顯示在其他應用程式上層」
+ 刪除檔案
+ 刪除條目
+ 已刪除條目
+ 帳號已終止\n\n%1$s 提供了理由:%2$s
+ 播放時收到來自伺服器的 HTTP 錯誤 403,可能因串流網址過期或 IP 封鎖所致
+ 播放時收到來自伺服器的 HTTP 錯誤 %1$s
+ 播放時收到來自伺服器的 HTTP 錯誤 403,可能因 IP 封鎖或串流網址去混淆化問題所致
+ %1$s 拒絕提供資料,要求登入以確認請求者並非機器人。\n\n您的 IP 位址可能已被 %1$s 暫時封鎖,您可稍候片刻或切換至其他 IP 位址(例如開啟/關閉 VPN,或從 Wi-Fi 切換至行動數據)。
+ 此內容目前無法於您所選的國家/地區提供。\n\n請至「設定」→「內容」→「預設內容國家」變更您的選擇。
diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml
index 352e4cec1..ab6e9e345 100644
--- a/app/src/main/res/values/settings_keys.xml
+++ b/app/src/main/res/values/settings_keys.xml
@@ -479,6 +479,7 @@
popup_player
download
add_to_playlist
+ enqueue
always_ask_player
@@ -488,6 +489,7 @@
- @string/popup_player
- @string/download
- @string/add_to_playlist
+ - @string/enqueue_stream
- @string/always_ask_open_action
@@ -498,6 +500,7 @@
- @string/download_key
- @string/add_to_playlist_key
- @string/always_ask_open_action_key
+ - @string/enqueue_key
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 57f78c221..147c88938 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -257,6 +257,8 @@
Restore defaults
Do you want to restore defaults?
Give permission to display over other apps
+ In order to use the Popup Player, please select %1$s in the following Android settings menu and enable %2$s.
+ “Allow display over other apps”
NewPipe encountered an error, tap to report
An error occurred, see the notification
@@ -287,9 +289,9 @@
Video
Audio
Retry
- k
- M
- B
+ %sK
+ %sM
+ %sB
Toggle service, currently selected:
No subscribers
@@ -333,6 +335,8 @@
Pause
Create
Delete
+ Delete file
+ Delete entry
Checksum
Dismiss
Rename
@@ -753,7 +757,7 @@
This content is private, so it cannot be streamed or downloaded by NewPipe.
This video is available only to YouTube Music Premium members, so it cannot be streamed or downloaded by NewPipe.
Account terminated
- %s provides this reason:
+ Account terminated\n\n%1$s provides this reason: %2$s
This content is only available to users who have paid, so it cannot be streamed or downloaded by NewPipe.
Featured
Radio
@@ -872,4 +876,10 @@
Trending podcasts
Trending movies and shows
Trending music
+ Entry deleted
+ HTTP error 403 received from server while playing, likely caused by streaming URL expiration or an IP ban
+ HTTP error %1$s received from server while playing
+ HTTP error 403 received from server while playing, likely caused by an IP ban or streaming URL deobfuscation issues
+ %1$s refused to provide data, asking for a login to confirm the requester is not a bot.\n\nYour IP might have been temporarily banned by %1$s, you can wait some time or switch to a different IP (for example by turning on/off a VPN, or by switching from WiFi to mobile data).
+ This content is not available for the currently selected content country.\n\nChange your selection from \"Settings > Content > Default content country\".
diff --git a/app/src/main/res/xml/video_audio_settings.xml b/app/src/main/res/xml/video_audio_settings.xml
index 727ce4df4..6e8e2979b 100644
--- a/app/src/main/res/xml/video_audio_settings.xml
+++ b/app/src/main/res/xml/video_audio_settings.xml
@@ -62,7 +62,7 @@
app:useSimpleSummaryProvider="true" />
localPlaylists = new ArrayList<>();
- final List remotePlaylists = new ArrayList<>();
- final List mergedPlaylists =
- MergedPlaylistManager.merge(localPlaylists, remotePlaylists);
-
- assertEquals(0, mergedPlaylists.size());
- }
-
- @Test
- public void onlyLocalPlaylists() {
- final List localPlaylists = new ArrayList<>();
- final List remotePlaylists = new ArrayList<>();
- localPlaylists.add(new PlaylistMetadataEntry(1, "name1", "", false, -1, 0, 1));
- localPlaylists.add(new PlaylistMetadataEntry(2, "name2", "", false, -1, 1, 1));
- localPlaylists.add(new PlaylistMetadataEntry(3, "name3", "", false, -1, 3, 1));
- final List mergedPlaylists =
- MergedPlaylistManager.merge(localPlaylists, remotePlaylists);
-
- assertEquals(3, mergedPlaylists.size());
- assertEquals(0, mergedPlaylists.get(0).getDisplayIndex());
- assertEquals(1, mergedPlaylists.get(1).getDisplayIndex());
- assertEquals(3, mergedPlaylists.get(2).getDisplayIndex());
- }
-
- @Test
- public void onlyRemotePlaylists() {
- final List localPlaylists = new ArrayList<>();
- final List remotePlaylists = new ArrayList<>();
- remotePlaylists.add(new PlaylistRemoteEntity(
- 1, "name1", "url1", "", "", 1, 1L));
- remotePlaylists.add(new PlaylistRemoteEntity(
- 2, "name2", "url2", "", "", 2, 1L));
- remotePlaylists.add(new PlaylistRemoteEntity(
- 3, "name3", "url3", "", "", 4, 1L));
- final List mergedPlaylists =
- MergedPlaylistManager.merge(localPlaylists, remotePlaylists);
-
- assertEquals(3, mergedPlaylists.size());
- assertEquals(1, mergedPlaylists.get(0).getDisplayIndex());
- assertEquals(2, mergedPlaylists.get(1).getDisplayIndex());
- assertEquals(4, mergedPlaylists.get(2).getDisplayIndex());
- }
-
- @Test
- public void sameIndexWithDifferentName() {
- final List localPlaylists = new ArrayList<>();
- final List remotePlaylists = new ArrayList<>();
- localPlaylists.add(new PlaylistMetadataEntry(1, "name1", "", false, -1, 0, 1));
- localPlaylists.add(new PlaylistMetadataEntry(2, "name2", "", false, -1, 1, 1));
- remotePlaylists.add(new PlaylistRemoteEntity(
- 1, "name3", "url1", "", "", 0, 1L));
- remotePlaylists.add(new PlaylistRemoteEntity(
- 2, "name4", "url2", "", "", 1, 1L));
- final List mergedPlaylists =
- MergedPlaylistManager.merge(localPlaylists, remotePlaylists);
-
- assertEquals(4, mergedPlaylists.size());
- assertTrue(mergedPlaylists.get(0) instanceof PlaylistMetadataEntry);
- assertEquals("name1", ((PlaylistMetadataEntry) mergedPlaylists.get(0)).name);
- assertTrue(mergedPlaylists.get(1) instanceof PlaylistRemoteEntity);
- assertEquals("name3", ((PlaylistRemoteEntity) mergedPlaylists.get(1)).getName());
- assertTrue(mergedPlaylists.get(2) instanceof PlaylistMetadataEntry);
- assertEquals("name2", ((PlaylistMetadataEntry) mergedPlaylists.get(2)).name);
- assertTrue(mergedPlaylists.get(3) instanceof PlaylistRemoteEntity);
- assertEquals("name4", ((PlaylistRemoteEntity) mergedPlaylists.get(3)).getName());
- }
-
- @Test
- public void sameNameWithDifferentIndex() {
- final List localPlaylists = new ArrayList<>();
- final List remotePlaylists = new ArrayList<>();
- localPlaylists.add(new PlaylistMetadataEntry(1, "name1", "", false, -1, 1, 1));
- localPlaylists.add(new PlaylistMetadataEntry(2, "name2", "", false, -1, 3, 1));
- remotePlaylists.add(new PlaylistRemoteEntity(
- 1, "name1", "url1", "", "", 0, 1L));
- remotePlaylists.add(new PlaylistRemoteEntity(
- 2, "name2", "url2", "", "", 2, 1L));
- final List mergedPlaylists =
- MergedPlaylistManager.merge(localPlaylists, remotePlaylists);
-
- assertEquals(4, mergedPlaylists.size());
- assertTrue(mergedPlaylists.get(0) instanceof PlaylistRemoteEntity);
- assertEquals("name1", ((PlaylistRemoteEntity) mergedPlaylists.get(0)).getName());
- assertTrue(mergedPlaylists.get(1) instanceof PlaylistMetadataEntry);
- assertEquals("name1", ((PlaylistMetadataEntry) mergedPlaylists.get(1)).name);
- assertTrue(mergedPlaylists.get(2) instanceof PlaylistRemoteEntity);
- assertEquals("name2", ((PlaylistRemoteEntity) mergedPlaylists.get(2)).getName());
- assertTrue(mergedPlaylists.get(3) instanceof PlaylistMetadataEntry);
- assertEquals("name2", ((PlaylistMetadataEntry) mergedPlaylists.get(3)).name);
- }
-}
diff --git a/app/src/test/java/org/schabi/newpipe/database/playlist/PlaylistLocalItemTest.kt b/app/src/test/java/org/schabi/newpipe/database/playlist/PlaylistLocalItemTest.kt
new file mode 100644
index 000000000..ace51e7e2
--- /dev/null
+++ b/app/src/test/java/org/schabi/newpipe/database/playlist/PlaylistLocalItemTest.kt
@@ -0,0 +1,102 @@
+/*
+ * SPDX-FileCopyrightText: 2022-2024 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package org.schabi.newpipe.database.playlist
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity
+import org.schabi.newpipe.local.bookmark.MergedPlaylistManager
+
+class PlaylistLocalItemTest {
+
+ @Test
+ fun emptyPlaylists() {
+ val localPlaylists = listOf()
+ val remotePlaylists = listOf()
+ val mergedPlaylists = MergedPlaylistManager.merge(localPlaylists, remotePlaylists)
+ assertEquals(0, mergedPlaylists.size)
+ }
+
+ @Test
+ fun onlyLocalPlaylists() {
+ val localPlaylists = listOf(
+ PlaylistMetadataEntry(1, "name1", "", 0, false, -1, 1),
+ PlaylistMetadataEntry(2, "name2", "", 1, false, -1, 1),
+ PlaylistMetadataEntry(3, "name3", "", 3, false, -1, 1)
+ )
+ val remotePlaylists = listOf()
+ val mergedPlaylists = MergedPlaylistManager.merge(localPlaylists, remotePlaylists)
+
+ assertEquals(3, mergedPlaylists.size)
+ assertEquals(0L, mergedPlaylists[0]!!.displayIndex)
+ assertEquals(1L, mergedPlaylists[1]!!.displayIndex)
+ assertEquals(3L, mergedPlaylists[2]!!.displayIndex)
+ }
+
+ @Test
+ fun onlyRemotePlaylists() {
+ val localPlaylists = listOf()
+ val remotePlaylists = listOf(
+ PlaylistRemoteEntity(1, 1, "name1", "url1", "", "", 1, 1),
+ PlaylistRemoteEntity(2, 2, "name2", "url2", "", "", 2, 1),
+ PlaylistRemoteEntity(3, 3, "name3", "url3", "", "", 4, 1)
+ )
+ val mergedPlaylists = MergedPlaylistManager.merge(localPlaylists, remotePlaylists)
+
+ assertEquals(3, mergedPlaylists.size)
+ assertEquals(1L, mergedPlaylists[0]!!.displayIndex)
+ assertEquals(2L, mergedPlaylists[1]!!.displayIndex)
+ assertEquals(4L, mergedPlaylists[2]!!.displayIndex)
+ }
+
+ @Test
+ fun sameIndexWithDifferentName() {
+ val localPlaylists = listOf(
+ PlaylistMetadataEntry(1, "name1", "", 0, false, -1, 1),
+ PlaylistMetadataEntry(2, "name2", "", 1, false, -1, 1)
+ )
+ val remotePlaylists = listOf(
+ PlaylistRemoteEntity(1, 1, "name3", "url1", "", "", 0, 1),
+ PlaylistRemoteEntity(2, 2, "name4", "url2", "", "", 1, 1)
+ )
+ val mergedPlaylists = MergedPlaylistManager.merge(localPlaylists, remotePlaylists)
+
+ assertEquals(4, mergedPlaylists.size)
+ assertTrue(mergedPlaylists[0] is PlaylistMetadataEntry)
+ assertEquals("name1", (mergedPlaylists[0] as PlaylistMetadataEntry).orderingName)
+ assertTrue(mergedPlaylists[1] is PlaylistRemoteEntity)
+ assertEquals("name3", (mergedPlaylists[1] as PlaylistRemoteEntity).orderingName)
+ assertTrue(mergedPlaylists[2] is PlaylistMetadataEntry)
+ assertEquals("name2", (mergedPlaylists[2] as PlaylistMetadataEntry).orderingName)
+ assertTrue(mergedPlaylists[3] is PlaylistRemoteEntity)
+ assertEquals("name4", (mergedPlaylists[3] as PlaylistRemoteEntity).orderingName)
+ }
+
+ @Test
+ fun sameNameWithDifferentIndex() {
+ val localPlaylists = listOf(
+ PlaylistMetadataEntry(1, "name1", "", 1, false, -1, 1),
+ PlaylistMetadataEntry(2, "name2", "", 3, false, -1, 1)
+ )
+ val remotePlaylists = listOf(
+ PlaylistRemoteEntity(1, 1, "name1", "url1", "", "", 0, 1),
+ PlaylistRemoteEntity(2, 2, "name2", "url2", "", "", 2, 1)
+ )
+ val mergedPlaylists = MergedPlaylistManager.merge(localPlaylists, remotePlaylists)
+
+ assertEquals(4, mergedPlaylists.size)
+ assertTrue(mergedPlaylists[0] is PlaylistRemoteEntity)
+ assertEquals("name1", (mergedPlaylists[0] as PlaylistRemoteEntity).orderingName)
+ assertTrue(mergedPlaylists[1] is PlaylistMetadataEntry)
+ assertEquals("name1", (mergedPlaylists[1] as PlaylistMetadataEntry).orderingName)
+ assertTrue(mergedPlaylists[2] is PlaylistRemoteEntity)
+ assertEquals("name2", (mergedPlaylists[2] as PlaylistRemoteEntity).orderingName)
+ assertTrue(mergedPlaylists[3] is PlaylistMetadataEntry)
+ assertEquals("name2", (mergedPlaylists[3] as PlaylistMetadataEntry).orderingName)
+ }
+}
diff --git a/app/src/test/java/org/schabi/newpipe/streams/SrtFromTtmlWriterTest.java b/app/src/test/java/org/schabi/newpipe/streams/SrtFromTtmlWriterTest.java
new file mode 100644
index 000000000..755724f68
--- /dev/null
+++ b/app/src/test/java/org/schabi/newpipe/streams/SrtFromTtmlWriterTest.java
@@ -0,0 +1,320 @@
+package org.schabi.newpipe.streams;
+
+import org.junit.Test;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.nodes.Node;
+import org.jsoup.parser.Parser;
+import java.io.ByteArrayInputStream;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for {@link SrtFromTtmlWriter}.
+ *
+ * Tests focus on {@code extractText()} and its handling of TTML elements.
+ * Note:
+ * - Uses reflection to call the private {@code extractText()} method.
+ * - Update {@code EXTRACT_TEXT_METHOD} if renamed.
+ *
+ * ---
+ * NOTE ABOUT ENTITIES VS UNICODE ESCAPES
+ *
+ * - In short:
+ * * UNICODE ESCAPES → used in Java source (e.g. SrtFromTtmlWriter.java)
+ * * ENTITIES → used in TTML strings (this test file)
+ *
+ * - TTML is an XML-based format. Real TTML subtitles often encode special
+ * characters as XML entities (named or numeric), e.g.:
+ * & → '&' (\u0026)
+ * < → '<' (\u003C)
+ * → tab (\u0009)
+ *
→ line feed (\u000A)
+ *
→ carriage return (\u000D)
+ *
+ * - Java source code uses **Unicode escapes** (e.g. "\u00A0") which are resolved
+ * at compile time, so they do not represent real XML entities.
+ *
+ * - Purpose of these tests:
+ * We simulate *real TTML input* as NewPipe receives it — i.e., strings that
+ * still contain encoded XML entities ( ,
,
, etc.).
+ * The production code (`decodeXmlEntities()`) must convert these into their
+ * actual Unicode characters before normalization.
+ */
+public class SrtFromTtmlWriterTest {
+ private static final String TTML_WRAPPER_START = "
";
+ private static final String TTML_WRAPPER_END = "
";
+ private static final String EXTRACT_TEXT_METHOD = "extractText";
+ // Please keep the same definition from `SrtFromTtmlWriter` class.
+ private static final String NEW_LINE = "\r\n";
+
+ /*
+ * TTML example for simple paragraph
without nested tags.
+ *
Hello World!
+ */
+ private static final String SIMPLE_TTML = "Hello World!
";
+ /**
+ * TTML example with nested tags with
.
+ * Hello
World!
+ */
+ private static final String NESTED_TTML = ""
+ + "Hello
World!
";
+
+ /**
+ * TTML example with HTML entities.
+ * < → <, > → >, & → &, " → ", ' → '
+ * ' → '
+ * → ' '
+ */
+ private static final String ENTITY_TTML = ""
+ + "<tag> & "text"''''"
+ + " "
+ + "
";
+ /**
+ * TTML example with special characters:
+ * - Spaces appear at the beginning and end of the text.
+ * - Spaces are also present within the text (not just at the edges).
+ * - The text includes various HTML entities such as ,
+ * &, <, >, etc.
+ * → non-breaking space (Unicode: '\u00A0', Entity: ' ')
+ */
+ private static final String SPECIAL_TTML = ""
+ + " ~~-Hello &&<<>>World!! "
+ + "
";
+
+ /**
+ * TTML example with characters: tab.
+ * → \t
+ * They are separated by '+' for clarity.
+ */
+ private static final String TAB_TTML = ""
+ + " + + "
+ + "
";
+
+ /**
+ * TTML example with line endings.
+ *
→ \r
+ */
+ private static final String LINE_ENDING_0_TTML = ""
+ + "
+
+
"
+ + "
";
+ //
→ \n
+ private static final String LINE_ENDING_1_TTML = ""
+ + "
+
+
"
+ + "
";
+ private static final String LINE_ENDING_2_TTML =
+ ""
+ + "
+
+
"
+ + "
";
+
+ /**
+ * TTML example with control characters.
+ * For example:
+ * → \u0001
+ * → \u001F
+ *
+ * These control characters, if included as raw Unicode(e.g. '\u0001'),
+ * are either invalid in XML or rendered as '?' when processed.
+ * To avoid issues, they should be encoded(e.g. '') in TTML file.
+ *
+ * - Reference:
+ * Unicode Basic Latin (https://unicode.org/charts/PDF/U0000.pdf),
+ * ASCII Control (https://en.wikipedia.org/wiki/ASCII#Control_characters).
+ * and the defination of these characters can be known.
+ */
+ private static final String CONTROL_CHAR_TTML = ""
+ + "+++++"
+ + "
";
+
+
+
+ private static final String EMPTY_TTML = ""
+ + ""
+ + "
";
+
+ /**
+ * TTML example with Unicode space characters.
+ * These characters are encoded using character references
+ * (XXXX;).
+ *
+ * Includes:
+ * ( ) '\u202F' → Narrow no-break space
+ * ( ) '\u205F' → Medium mathematical space
+ * ( ) '\u3000' → Ideographic space
+ * '\u2000' ~ '\u200A' are whitespace characters:
+ * ( ) '\u2000' → En quad
+ * ( ) '\u2002' → En space
+ * ( ) '\u200A' → Hair space
+ *
+ * Each character is separated by '+' for clarity.
+ */
+ private static final String UNICODE_SPACE_TTML = ""
+ + " + + + + + "
+ + "
";
+
+ /**
+ * TTML example with non-spacing (invisible) characters.
+ * These are encoded using character references (XXXX;).
+ *
+ * Includes:
+ * ()'\u200B' → Zero-width space (ZWSP)
+ * ()'\u200E' → Left-to-right mark (LRM)
+ * ()'\u200F' → Right-to-left mark (RLM)
+ *
+ * They don't display any characters to the human eye.
+ * '+' is used between them for clarity in test output.
+ */
+ private static final String NON_SPACING_TTML = ""
+ + "++"
+ + "
";
+
+ /**
+ * Parses TTML string into a JSoup Document and selects the first element.
+ *
+ * @param ttmlContent TTML content (e.g.,
...
)
+ * @return the first element
+ * @throws Exception if parsing or reflection fails
+ */
+ private Element parseTtmlParagraph(final String ttmlContent) throws Exception {
+ final String ttml = TTML_WRAPPER_START + ttmlContent + TTML_WRAPPER_END;
+ final Document doc = Jsoup.parse(
+ new ByteArrayInputStream(ttml.getBytes(StandardCharsets.UTF_8)),
+ "UTF-8", "", Parser.xmlParser());
+ return doc.select("body > div > p").first();
+ }
+
+ /**
+ * Invokes private extractText method via reflection.
+ *
+ * @param writer SrtFromTtmlWriter instance
+ * @param paragraph
element to extract text from
+ * @param text StringBuilder to store extracted text
+ * @throws Exception if reflection fails
+ */
+ private void invokeExtractText(final SrtFromTtmlWriter writer, final Element paragraph,
+ final StringBuilder text) throws Exception {
+ final Method method = writer.getClass()
+ .getDeclaredMethod(EXTRACT_TEXT_METHOD, Node.class, StringBuilder.class);
+ method.setAccessible(true);
+ method.invoke(writer, paragraph, text);
+ }
+
+ private String extractTextFromTtml(final String ttmlInput) throws Exception {
+ final Element paragraph = parseTtmlParagraph(ttmlInput);
+ final StringBuilder text = new StringBuilder();
+ final SrtFromTtmlWriter writer = new SrtFromTtmlWriter(null, false);
+ invokeExtractText(writer, paragraph, text);
+
+ final String actualText = text.toString();
+ return actualText;
+ }
+
+ @Test
+ public void testExtractTextSimpleParagraph() throws Exception {
+ final String expected = "Hello World!";
+ final String actual = extractTextFromTtml(SIMPLE_TTML);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testExtractTextNestedTags() throws Exception {
+ final String expected = "Hello\r\nWorld!";
+ final String actual = extractTextFromTtml(NESTED_TTML);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testExtractTextWithEntity() throws Exception {
+ final String expected = " & \"text\"'''' ";
+ final String actual = extractTextFromTtml(ENTITY_TTML);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testExtractTextWithSpecialCharacters() throws Exception {
+ final String expected = " ~~-Hello &&<<>>World!! ";
+ final String actual = extractTextFromTtml(SPECIAL_TTML);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testExtractTextWithTab() throws Exception {
+ final String expected = " + + ";
+ final String actual = extractTextFromTtml(TAB_TTML);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testExtractTextWithLineEnding0() throws Exception {
+ final String expected = NEW_LINE + NEW_LINE + "+"
+ + NEW_LINE + NEW_LINE + "+"
+ + NEW_LINE + NEW_LINE;
+ final String actual = extractTextFromTtml(LINE_ENDING_0_TTML);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testExtractTextWithLineEnding1() throws Exception {
+ final String expected = NEW_LINE + NEW_LINE + "+"
+ + NEW_LINE + NEW_LINE + "+"
+ + NEW_LINE + NEW_LINE;
+ final String actual = extractTextFromTtml(LINE_ENDING_1_TTML);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testExtractTextWithLineEnding2() throws Exception {
+ final String expected = NEW_LINE + "+"
+ + NEW_LINE + "+"
+ + NEW_LINE;
+ final String actual = extractTextFromTtml(LINE_ENDING_2_TTML);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testExtractTextWithControlCharacters() throws Exception {
+ final String expected = "+++++";
+ final String actual = extractTextFromTtml(CONTROL_CHAR_TTML);
+ assertEquals(expected, actual);
+ }
+
+ /**
+ * Test case to ensure that extractText() does not throw an exception
+ * when there are no text in the TTML paragraph (i.e., the paragraph
+ * is empty).
+ *
+ * Note:
+ * In the NewPipe, *.srt files will contain empty text lines by default.
+ */
+ @Test
+ public void testExtractTextWithEmpty() throws Exception {
+ final String expected = "";
+ final String actual = extractTextFromTtml(EMPTY_TTML);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testExtractTextWithUnicodeSpaces() throws Exception {
+ final String expected = " + + + + + ";
+ final String actual = extractTextFromTtml(UNICODE_SPACE_TTML);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testExtractTextWithNonSpacingCharacters() throws Exception {
+ final String expected = "++";
+ final String actual = extractTextFromTtml(NON_SPACING_TTML);
+ assertEquals(expected, actual);
+ }
+}
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index d93abc4c0..000000000
--- a/build.gradle
+++ /dev/null
@@ -1,25 +0,0 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
-buildscript {
- ext.kotlin_version = '1.9.25'
- repositories {
- google()
- mavenCentral()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:8.7.1'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
-
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
- }
-}
-
-allprojects {
- repositories {
- google()
- mavenCentral()
- maven { url "https://jitpack.io" }
- maven { url "https://repo.clojars.org" }
- }
-}
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 000000000..2c9173f57
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,13 @@
+/*
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+plugins {
+ alias(libs.plugins.android.application) apply false
+ alias(libs.plugins.jetbrains.kotlin.android) apply false
+ alias(libs.plugins.jetbrains.kotlin.kapt) apply false
+ alias(libs.plugins.google.ksp) apply false
+ alias(libs.plugins.jetbrains.kotlin.parcelize) apply false
+ alias(libs.plugins.sonarqube) apply false
+}
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
new file mode 100644
index 000000000..713cead4b
--- /dev/null
+++ b/buildSrc/build.gradle.kts
@@ -0,0 +1,12 @@
+/*
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+plugins {
+ `kotlin-dsl`
+}
+
+repositories {
+ gradlePluginPortal()
+}
diff --git a/buildSrc/src/main/kotlin/CheckDependenciesOrder.kt b/buildSrc/src/main/kotlin/CheckDependenciesOrder.kt
new file mode 100644
index 000000000..8bf92d8cd
--- /dev/null
+++ b/buildSrc/src/main/kotlin/CheckDependenciesOrder.kt
@@ -0,0 +1,68 @@
+/*
+ * SPDX-FileCopyrightText: 2024 NewPipe contributors
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.file.RegularFileProperty
+import org.gradle.api.tasks.InputFile
+import org.gradle.api.tasks.TaskAction
+
+abstract class CheckDependenciesOrder : DefaultTask() {
+
+ @get:InputFile
+ abstract val tomlFile: RegularFileProperty
+
+ init {
+ group = "verification"
+ description = "Checks that each section in libs.versions.toml is sorted alphabetically"
+ }
+
+ @TaskAction
+ fun run() {
+ val file = tomlFile.get().asFile
+ if (!file.exists()) error("TOML file not found")
+
+ val lines = file.readLines()
+ val nonSortedBlocks = mutableListOf>()
+ var currentBlock = mutableListOf()
+ var prevLine = ""
+ var prevIndex = 0
+
+ lines.forEachIndexed { lineIndex, line ->
+ if (line.trim().isNotEmpty() && !line.startsWith("#")) {
+ if (line.startsWith("[")) {
+ prevLine = ""
+ } else {
+ val currIndex = lineIndex + 1
+ if (prevLine > line) {
+ if (currentBlock.isNotEmpty() && currentBlock.last() == "$prevIndex: $prevLine") {
+ currentBlock.add("$currIndex: $line")
+ } else {
+ if (currentBlock.isNotEmpty()) {
+ nonSortedBlocks.add(currentBlock)
+ currentBlock = mutableListOf()
+ }
+ currentBlock.add("$prevIndex: $prevLine")
+ currentBlock.add("$currIndex: $line")
+ }
+ }
+ prevLine = line
+ prevIndex = lineIndex + 1
+ }
+ }
+ }
+
+ if (currentBlock.isNotEmpty()) {
+ nonSortedBlocks.add(currentBlock)
+ }
+
+ if (nonSortedBlocks.isNotEmpty()) {
+ error(
+ "The following lines were not sorted:\n" +
+ nonSortedBlocks.joinToString("\n\n") { it.joinToString("\n") }
+ )
+ }
+ }
+}
diff --git a/fastlane/metadata/android/bg/changelogs/1000.txt b/fastlane/metadata/android/bg/changelogs/1000.txt
new file mode 100644
index 000000000..fea57c3d5
--- /dev/null
+++ b/fastlane/metadata/android/bg/changelogs/1000.txt
@@ -0,0 +1,13 @@
+Подобрено
+• Направи описанието на плейлиста възможно за избиране за показване на повече/по-малко съдържание
+• [PeerTube] Поддръжка
+`subscribeto.me` инстанцията се свързва автоматично
+• Пускай само един обект в екрана за история
+Поправено
+• Поправи видимостта на RSS бутона
+• Поправи сриване на предварителния преглед на полето за търсене
+• Поправи показването на обект без обложка
+• Поправено е излизането от диалоговия прозорец за изтегляне, преди да се появи
+• Поправка на изскачащ прозорец за добавяне в опашката на списък със свързани елементи
+• Поправка на реда в диалоговия прозорец за добавяне към плейлиста
+• Регулиране на оформлението на елементите от отметките в плейлиста
diff --git a/fastlane/metadata/android/bg/changelogs/63.txt b/fastlane/metadata/android/bg/changelogs/63.txt
deleted file mode 100644
index be8865e6d..000000000
--- a/fastlane/metadata/android/bg/changelogs/63.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-### Подобрения
-- Импорт/ Експорт на настройки #1333
-- Редуциране на надхвърляне (подобрение на производителността) #1371
-- Малки подобрения в кода #1375
-- Добавяне на всичко за GDPR #1420
-
-### Поправени
-- Изтегляния: Поправен срив при зареждане на неприключени изтегляния от .giga файлове #1407
diff --git a/fastlane/metadata/android/bs/changelogs/1000.txt b/fastlane/metadata/android/bs/changelogs/1000.txt
new file mode 100644
index 000000000..41bcd963e
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/1000.txt
@@ -0,0 +1,13 @@
+Poboljšano
+• Opis liste za reprodukciju učinite klikom za prikaz više/manje sadržaja
+• [PeerTube] Automatski obrađuje linkove instanci `subscribeto.me`
+• Pokreni reprodukciju samo jedne stavke na ekranu historije
+
+Ispravljeno
+• Ispravljena vidljivost RSS dugmeta
+• Ispravljeno rušenje pregleda trake za pretraživanje
+• Ispravljena stavka bez sličice prilikom dodavanja na listu za reprodukciju
+• Ispravljeno izlaženje iz dijaloga za preuzimanje prije nego što se pojavi
+• Ispravljen skočni prozor za dodavanje u red čekanja za povezane stavke
+• Ispravljen redoslijed u dijalogu za dodavanje na listu za reprodukciju
+• Prilagodite raspored stavki označenih na listi za reprodukciju
diff --git a/fastlane/metadata/android/bs/changelogs/1001.txt b/fastlane/metadata/android/bs/changelogs/1001.txt
new file mode 100644
index 000000000..f798a0a78
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/1001.txt
@@ -0,0 +1,6 @@
+Poboljšano
+• Uvijek dozvoli promjenu postavki obavještenja igrača na Androidu 13+
+
+Ispravljeno
+• Ispravljena greška izvoza baze podataka/pretplata koja nije skraćivala već postojeću datoteku, što je moglo dovesti do oštećenja izvoza
+• Ispravljeno ponovno pokretanje igrača od početka klikom na vremensku oznaku
diff --git a/fastlane/metadata/android/bs/changelogs/1002.txt b/fastlane/metadata/android/bs/changelogs/1002.txt
new file mode 100644
index 000000000..5fc0b843a
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/1002.txt
@@ -0,0 +1,4 @@
+Ispravljena greška zbog koje YouTube nije reproducirao nijedan tok.
+
+Ovo izdanje rješava samo najhitniju grešku koja sprječava učitavanje detalja YouTube videa.
+Svjesni smo da postoje i drugi problemi i uskoro ćemo objaviti zasebno izdanje kako bismo ih riješili.
diff --git a/fastlane/metadata/android/bs/changelogs/1003.txt b/fastlane/metadata/android/bs/changelogs/1003.txt
new file mode 100644
index 000000000..45a0e5739
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/1003.txt
@@ -0,0 +1,6 @@
+Ovo je hitna ispravka koja ispravlja greške na YouTubeu:
+• [YouTube] Ispravljeno neučitavanje informacija o videozapisu, ispravljene greške HTTP 403 prilikom reprodukcije videozapisa i vraćanje reprodukcije nekih videozapisa s ograničenjem za uzrast
+• Ispravljena veličina titlova koja se nije mijenjala
+• Ispravljeno dvostruko preuzimanje informacija prilikom otvaranja toka
+• [Soundcloud] Uklonjeni nereproducirani tokovi zaštićeni DRM-om
+• Ažurirani prijevodi
diff --git a/fastlane/metadata/android/bs/changelogs/1004.txt b/fastlane/metadata/android/bs/changelogs/1004.txt
new file mode 100644
index 000000000..bbd4fb0a0
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/1004.txt
@@ -0,0 +1,3 @@
+Ovo izdanje ispravlja problem sa YouTube-om koji pruža samo 360p tok.
+
+Imajte na umu da je rješenje korišteno u ovoj verziji vjerovatno privremeno i da dugoročno gledano treba implementirati SABR video protokol, ali članovi TeamNewPipe-a su trenutno zauzeti, tako da bi svaka pomoć bila veoma cijenjena! https://github.com/TeamNewPipe/NewPipe/issues/12248
diff --git a/fastlane/metadata/android/bs/changelogs/1005.txt b/fastlane/metadata/android/bs/changelogs/1005.txt
new file mode 100644
index 000000000..4d98c6dac
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/1005.txt
@@ -0,0 +1,17 @@
+Novo
+• Dodata podrška za Android Auto
+• Omogućeno postavljanje grupa feedova kao kartica na glavnom ekranu
+• [YouTube] Dijeli kao privremenu listu za reprodukciju
+• [SoundCloud] Kartica kanala sa sviđanjima
+
+Poboljšano
+• Bolji savjeti u traci za pretragu
+• Prikaz datuma preuzimanja u Preuzimanjema
+• Korištenje jezika Androida 13 po aplikaciji
+
+Ispravljeno
+• Ispravljene boje teksta koje ne rade u tamnom režimu
+• [YouTube] Ispravljeno liste za reprodukciju koje ne učitavaju više od 100 stavki
+• [YouTube] Ispravljeni nedostajući preporučeni videozapisi
+• Ispravljeni rušenja u prikazu liste historije
+• Ispravljene vremenske oznake u odgovorima na komentare
diff --git a/fastlane/metadata/android/bs/changelogs/64.txt b/fastlane/metadata/android/bs/changelogs/64.txt
new file mode 100644
index 000000000..f0fff6468
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/64.txt
@@ -0,0 +1,8 @@
+### Poboljšanja
+- Dodata je mogućnost ograničavanja kvalitete videa ako se koriste mobilni podaci. #1339
+- Zapamti svjetlinu za sesiju #1442
+- Poboljšane performanse preuzimanja za slabije procesore #1431
+- dodana (funkcionalna) podrška za medijsku sesiju #1433
+
+### Ispravka
+- Ispravljen pad sistema prilikom otvaranja preuzimanja (ispravka je sada dostupna za izdane verzije) #1441
diff --git a/fastlane/metadata/android/bs/changelogs/65.txt b/fastlane/metadata/android/bs/changelogs/65.txt
new file mode 100644
index 000000000..9efa1420b
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/65.txt
@@ -0,0 +1,26 @@
+### Poboljšanja
+
+- Onemogućavanje animacije ikone burgermenuja #1486
+- poništavanje brisanja preuzimanja #1472
+- Opcija preuzimanja u meniju za dijeljenje #1498
+- Dodata opcija dijeljenja u meni s dugim dodirom #1454
+- Minimiziranje glavnog playera pri izlasku #1354
+- Ispravka ažuriranja verzije biblioteke i sigurnosne kopije baze podataka #1510
+- Ažuriranje ExoPlayera 2.8.2 #1392
+- Prerađen dijalog za kontrolu brzine reprodukcije radi podrške za različite veličine koraka za bržu promjenu brzine.
+- Dodan je prekidač za premotavanje unaprijed tokom tišina u kontroli brzine reprodukcije. Ovo bi trebalo biti korisno za audio knjige i određene muzičke žanrove, a može donijeti zaista besprijekorno iskustvo (i može prekinuti pjesmu s puno tišina =\\).
+- Refaktorisana rezolucija izvora medija kako bi se omogućilo interno prosljeđivanje metapodataka uz medije u playeru, umjesto ručnog. Sada imamo jedan izvor metapodataka i direktno je dostupan kada reprodukcija počne.
+- Ispravljeni metapodaci udaljene liste za reprodukciju koji se ne ažuriraju kada su novi metapodaci dostupni kada se otvori fragment liste za reprodukciju.
+- Razne ispravke korisničkog interfejsa: #1383, kontrole obavještenja u pozadini playera sada su uvijek bijele, lakše je isključiti iskačući player prebacivanjem.
+- Koristi se novi ekstraktor s refaktoriranom arhitekturom za više servisa.
+
+### Ispravke
+
+- Ispravka #1440 Neispravan raspored informacija o videu #1491
+- Ispravka historije pregleda #1497
+- #1495, ažuriranjem metapodataka (sličica, naslov i broj videa) čim korisnik pristupi listi za reprodukciju.
+- #1475, registracijom pregleda u bazi podataka kada korisnik pokrene video na vanjskom playeru na fragmentu detalja.
+- Ispravljeno vremensko ograničenje ekrana u slučaju iskačućeg načina rada. #1463 (Ispravljeno #640)
+- Ispravka glavnog video playera #1509
+- [#1412] Ispravljen je način ponavljanja koji je uzrokovao NPE playera kada se primi nova namjera dok je aktivnost playera u pozadini.
+- Ispravljena je greška minimiziranja playera u iskačući prozor koja ne uništava player kada nije odobrena dozvola za iskačući prozor.
diff --git a/fastlane/metadata/android/bs/changelogs/66.txt b/fastlane/metadata/android/bs/changelogs/66.txt
new file mode 100644
index 000000000..0562b9059
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/66.txt
@@ -0,0 +1,33 @@
+# Dnevnik promjena v0.13.7
+
+### Ispravljeno
+- Ispravljeni problemi sa filterom sortiranja iz v0.13.6
+
+# Dnevnik promjena v0.13.6
+
+### Poboljšanja
+
+- Onemogućena animacija ikone burger menija #1486
+- poništavanje brisanja preuzimanja #1472
+- Opcija preuzimanja u meniju za dijeljenje #1498
+- Dodata opcija dijeljenja u meni dugog dodira #1454
+- Minimiziranje glavnog playera pri izlasku #1354
+- Ispravka ažuriranja verzije biblioteke i sigurnosne kopije baze podataka #1510
+- Ažuriranje ExoPlayera 2.8.2 #1392
+- Prerađen dijalog za kontrolu brzine reprodukcije kako bi se podržale različite veličine koraka za bržu promjenu brzine.
+- Dodan je prekidač za premotavanje unaprijed tokom tišina u kontroli brzine reprodukcije. Ovo bi trebalo biti korisno za audio knjige i određene muzičke žanrove i može donijeti zaista besprijekorno iskustvo (i može prekinuti pjesmu s puno tišina =\\).
+- Refaktorisana rezolucija izvora medija kako bi se omogućilo interno prosljeđivanje metapodataka zajedno s medijima u playeru, umjesto ručnog. Sada imamo jedan izvor metapodataka i on je direktno dostupan kada počne reprodukcija.
+- Ispravljeni metapodaci udaljene liste za reprodukciju koji se nisu ažurirali kada su novi metapodaci dostupni prilikom otvaranja fragmenta liste za reprodukciju.
+- Razne ispravke korisničkog interfejsa: #1383, kontrole obavještenja u pozadini playera sada su uvijek bijele, lakše je isključiti iskačući player prebacivanjem.
+- Koristi se novi ekstraktor s refaktorisanom arhitekturom za više servisa.
+
+### Ispravke
+
+- Ispravka #1440 Neispravan raspored informacija o videu #1491
+- Ispravka historije pregleda #1497
+- #1495, ažuriranjem metapodataka (sličica, naslov i broj videa) čim korisnik pristupi listi za reprodukciju.
+- #1475, registracijom pregleda u bazi podataka kada korisnik pokrene video na vanjskom playeru na fragmentu detalja.
+- Ispravljeno vremensko ograničenje ekrana u slučaju iskačućeg načina rada. #1463 (Ispravljeno #640)
+- Ispravka glavnog video plejera #1509
+- [#1412] Ispravljen je način ponavljanja koji je uzrokovao NPE plejera kada se primi nova namjera dok je aktivnost plejera u pozadini.
+- Ispravljeno je minimiziranje plejera u skočni prozor koje nije uništilo plejer kada nije odobrena dozvola za skočni prozor.
diff --git a/fastlane/metadata/android/bs/changelogs/68.txt b/fastlane/metadata/android/bs/changelogs/68.txt
new file mode 100644
index 000000000..8d1b80a9e
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/68.txt
@@ -0,0 +1,31 @@
+# promjene v0.14.1
+
+### Ispravljeno
+- Ispravljeno neuspješno dešifriranje URL-a videa #1659
+- Ispravljeno nije dobro izdvajanje linka opisa #1657
+
+# promjene v0.14.0
+
+### Novo
+- Novi dizajn ladice #1461
+- Nova prilagodljiva početna stranica #1461
+
+### Poboljšanja
+- Prerađene kontrole gestikulacije #1604
+- Novi način zatvaranja iskačućeg playera #1597
+
+### Ispravljeno
+- Ispravljena greška kada broj pretplata nije dostupan. Zatvara se #1649.
+- Prikaži "Broj pretplatnika nije dostupan" u tim slučajevima
+- Ispravljen NPE kada je YouTube lista za reprodukciju prazna
+- Brzo rješenje za kioske u SoundCloudu
+- Refaktoriranje i ispravka greške #1623
+- Ispravljen ciklički rezultat pretrage #1562
+- Ispravljena traka za pretraživanje koja nije statički postavljena
+- Ispravljeno YT Premium videozapisi nisu ispravno blokirani
+- Ispravljeno videozapisi koji se ponekad ne učitavaju (zbog DASH parsiranja)
+- Ispravljeni linkovi u opisu videozapisa
+- Prikaži upozorenje kada neko pokuša preuzeti na eksternu sd karticu
+- ispravljen izuzetak koji se ne prikazuje, a pokreće izvještaj
+- sličica se ne prikazuje u pozadinskom playeru za Android 8.1 [pogledajte ovdje](https://github.com/TeamNewPipe/NewPipe/issues/943)
+- Ispravljeno registracija prijemnika emitiranja. Zatvoreno #1641.
diff --git a/fastlane/metadata/android/bs/changelogs/69.txt b/fastlane/metadata/android/bs/changelogs/69.txt
new file mode 100644
index 000000000..27172b680
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/69.txt
@@ -0,0 +1,19 @@
+### Novo
+- Dugi dodir za brisanje i dijeljenje u pretplatama #1516
+- Korisnički interfejs tableta i raspored mreže #1617
+
+### Poboljšanja
+- pohranjivanje i ponovno učitavanje posljednjeg korištenog omjera širine i visine #1748
+- Omogućavanje linearnog rasporeda u aktivnosti preuzimanja s punim nazivima videozapisa #1771
+- Brisanje i dijeljenje pretplata direktno iz kartice pretplata #1516
+- Stavljanje u red čekanja sada pokreće reprodukciju videozapisa ako je red čekanja za reprodukciju već završen #1783
+- Odvojene postavke za geste jačine zvuka i svjetline #1644
+- Dodana podrška za lokalizaciju #1792
+
+### Ispravke
+- Ispravljeno raščlanjivanje vremena za . format, tako da se NewPipe može koristiti u Finskoj
+- Ispravljen broj pretplata
+- Dodana dozvola za uslugu u prvom planu za API 28+ uređaje #1830
+
+### Poznate greške
+- Stanje reprodukcije se ne može sačuvati na Android P
diff --git a/fastlane/metadata/android/bs/changelogs/70.txt b/fastlane/metadata/android/bs/changelogs/70.txt
new file mode 100644
index 000000000..d72ac7a04
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/70.txt
@@ -0,0 +1,25 @@
+PAŽNJA: Ova verzija je vjerovatno puna grešaka, baš kao i prethodna. Međutim, zbog potpunog gašenja od verzije 17, bolja je i pokvarena verzija nego nikakva. Zar ne? ¯\_(ツ)_/¯
+
+### Poboljšanja
+* preuzete datoteke se sada mogu otvoriti jednim klikom #1879
+* ukidanje podrške za Android 4.1 - 4.3 #1884
+* uklanjanje starog plejera #1884
+* uklanjanje tokova iz trenutnog reda čekanja prevlačenjem prsta udesno #1915
+* uklanjanje automatski dodanog toka u red čekanja kada se novi tok ručno doda u red čekanja #1878
+* Naknadna obrada preuzimanja i implementacija nedostajućih funkcija #1759 od @kapodamy
+* Infrastruktura naknadne obrade
+* Ispravna "infrastruktura" za rukovanje greškama (za program za preuzimanje)
+* Stavljanje u red čekanja umjesto više preuzimanja
+* Premještanje serijaliziranih preuzimanja na čekanju (`.giga` datoteke) u podatke aplikacije
+* Implementacija maksimalnog broja ponovnih pokušaja preuzimanja
+* Ispravno pauziranje preuzimanja u više niti
+* Zaustavljanje preuzimanja prilikom prebacivanja na mobilnu mrežu (nikada ne radi, pogledajte 2. tačku)
+* Sačuvanje broja niti za sljedeća preuzimanja
+* Mnogo nedosljednosti ispravljeno
+
+### Ispravljeno
+* Ispravljen pad sistema sa zadanom rezolucijom postavljenom na najbolju i ograničenom rezolucijom mobilnih podataka #1835
+* Ispravljen pad sistema prilikom iskačućeg plejera #1874
+* NPE pri pokušaju otvaranja pozadinskog plejera #1901
+* Ispravljeno umetanje novih tokova kada je omogućeno automatsko stavljanje u red #1878
+* Ispravljen problem sa dešifriranjem i isključivanjem sistema
diff --git a/fastlane/metadata/android/bs/changelogs/71.txt b/fastlane/metadata/android/bs/changelogs/71.txt
new file mode 100644
index 000000000..28a8ba733
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/71.txt
@@ -0,0 +1,10 @@
+### Poboljšanja
+* Dodana obavijest o ažuriranju aplikacije za GitHub verziju (#1608 od @krtkush)
+* Različita poboljšanja programa za preuzimanje (#1944 od @kapodamy):
+* dodane nedostajuće bijele ikone i korištenje ugrađenog načina za promjenu boja ikona
+* provjera da li je iterator inicijaliziran (ispravke #2031)
+* omogućava ponovni pokušaj preuzimanja s greškom "naknadna obrada nije uspjela" u novom multiplekseru
+* novi MPEG-4 multiplekser ispravlja nesinhrone video i audio tokove (#2039)
+
+### Ispravljeno
+* YouTube tokovi uživo prestaju s reprodukcijom nakon kratkog vremena (#1996 od @yausername)
diff --git a/fastlane/metadata/android/bs/changelogs/730.txt b/fastlane/metadata/android/bs/changelogs/730.txt
new file mode 100644
index 000000000..581435b63
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/730.txt
@@ -0,0 +1,2 @@
+# Ispravljeno
+- Ispravljena greška funkcije dešifriranja.
diff --git a/fastlane/metadata/android/bs/changelogs/740.txt b/fastlane/metadata/android/bs/changelogs/740.txt
new file mode 100644
index 000000000..ad72fe828
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/740.txt
@@ -0,0 +1 @@
+Poboljšanja
- učinite linkove u komentarima klikabilnim, povećajte veličinu teksta
- traži klikom na linkove vremenskih oznaka u komentarima
- prikaži preferiranu karticu na osnovu nedavno odabranog stanja
- dodaje listu pjesama u red čekanja kada se dugo klikne na 'Pozadina' u prozoru liste pjesama
- traži dijeljeni tekst kada nije URL
- Dodajte dugme "podijeli u trenutno vrijeme" u glavni video plejer
- dodajte dugme za zatvaranje u glavni plejer kada se završi red čekanja za video
- Dodajte "Reproduciraj direktno u pozadini" u meni s dugim pritiskom za stavke liste videozapisa
- poboljšati engleske prijevode za naredbe Play/Enqueue
- mala poboljšanja performansi
- uklonite nekorištene datoteke
- Ažurirajte ExoPlayer na verziju 2.9.6
- dodajte podršku za Invidious linkove
Fiksno
- Ispravljeno skrolovanje sa onemogućenim komentarima i povezanim tokovima
- ispravljena greška prilikom izvršavanja CheckForNewAppVersionTask-a kada ne bi trebalo
- Ispravljen uvoz pretplata na YouTube: ignorišite one sa nevažećim URL-om i zadržite one sa praznim naslovom
- Ispravljen nevažeći YouTube URL: naziv oznake potpisa nije uvijek "potpis", što sprječava učitavanje tokova
diff --git a/fastlane/metadata/android/bs/changelogs/750.txt b/fastlane/metadata/android/bs/changelogs/750.txt
new file mode 100644
index 000000000..dd043ae61
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/750.txt
@@ -0,0 +1,21 @@
+Novo
+Nastavak reprodukcije #2288
+• Nastavite tokove tamo gdje ste prošli put stali
+Poboljšanja programa za preuzimanje #2149
+• Koristite okvir za pristup pohrani za pohranu preuzimanja na eksterne SD kartice
+• Novi mp4 muxer
+• Opcionalno promijenite direktorij za preuzimanje prije početka preuzimanja
+• Poštujte mjerene mreže
+
+Poboljšano
+• Uklonjeni gema stringovi #2295
+• Obrađuje promjene (automatske) rotacije tokom životnog ciklusa aktivnosti #2444
+• Učinite menije s dugim pritiskom konzistentnim #2368
+
+Ispravljeno
+• Ispravljeno neprikazivanje naziva odabrane pjesme s titlovima #2394
+• Nije došlo do pada programa kada provjera ažuriranja aplikacije ne uspije (GitHub verzija) #2423
+• Ispravljena preuzimanja zaglavljena na 99,9% #2440
+• Ažuriranje metapodataka reda čekanja za reprodukciju #2453
+• [SoundCloud] Ispravljen pad programa prilikom učitavanja lista za reprodukciju TeamNewPipe/NewPipeExtractor#170
+• [YouTube] Fiksno trajanje se ne može parsirati TeamNewPipe/NewPipeExtractor#177
diff --git a/fastlane/metadata/android/bs/changelogs/760.txt b/fastlane/metadata/android/bs/changelogs/760.txt
new file mode 100644
index 000000000..ba5f26b1e
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/760.txt
@@ -0,0 +1,40 @@
+Promjene u verziji 0.17.1
+
+Novo
+• Tajlandska lokalizacija
+
+Poboljšano
+
+• Ponovo dodana akcija "počni reprodukciju ovdje" u menijima dugog pritiska za liste za reprodukciju #2518
+• Dodan prekidač za SAF / birač starih datoteka #2521
+
+Ispravljeno
+• Ispravljeni dugmad koja nestaju u prikazu preuzimanja prilikom prebacivanja aplikacija #2487
+• Ispravljena je greška u poziciji reprodukcije koja se pohranjuje iako je historija gledanja onemogućena
+• Ispravljene smanjene performanse uzrokovane pozicijom reprodukcije u prikazima liste #2517
+• [Extractor] Ispravljena je ReCaptchaActivity #2527, TeamNewPipe/NewPipeExtractor #186
+• [Extractor] [YouTube] Ispravljena je slučajna greška u pretrazi kada su liste za reprodukciju u rezultatima TeamNewPipe/NewPipeExtractor #185
+
+Promjene u verziji 0.17.0
+
+Novo
+Nastavak reprodukcije #2288
+• Nastavite tokove tamo gdje ste zadnji put stali
+Poboljšanja programa za preuzimanje #2149
+• Koristite okvir za pristup pohrani za pohranjivanje preuzimanja na eksterne SD kartice
+• Novi mp4 muxer
+• Opcionalno promijenite direktorij za preuzimanje prije početka preuzimanja
+• Poštujte mjerene mreže
+
+Poboljšano
+• Uklonjeni gema stringovi #2295
+• Obrađuje promjene (automatske) rotacije tokom životnog ciklusa aktivnosti #2444
+• Učinite menije s dugim pritiskom konzistentnim #2368
+
+Ispravljeno
+• Ispravljeno ime odabrane numere titlova koje se ne prikazuje #2394
+• Nije došlo do pada programa kada provjera ažuriranja aplikacije ne uspije (GitHub verzija) #2423
+• Ispravljena preuzimanja zaglavljena na 99,9% #2440
+• Ažuriranje metapodataka reda za reprodukciju #2453
+• [SoundCloud] Ispravljen pad programa prilikom učitavanja lista za reprodukciju TeamNewPipe/NewPipeExtractor#170
+• [YouTube] Fiksno trajanje se ne može parsirati TeamNewPipe/NewPipeExtractor#177
diff --git a/fastlane/metadata/android/bs/changelogs/770.txt b/fastlane/metadata/android/bs/changelogs/770.txt
new file mode 100644
index 000000000..e7d35d207
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/770.txt
@@ -0,0 +1,4 @@
+Promjene u verziji 0.17.2
+
+Ispravka
+• Ispravka da nijedan video nije bio dostupan
diff --git a/fastlane/metadata/android/bs/changelogs/780.txt b/fastlane/metadata/android/bs/changelogs/780.txt
new file mode 100644
index 000000000..6a1074369
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/780.txt
@@ -0,0 +1,12 @@
+Promjene u verziji 0.17.3
+
+Poboljšano
+• Dodata opcija za brisanje stanja reprodukcije #2550
+• Prikaz skrivenih direktorija u biraču datoteka #2591
+• Podrška za otvaranje URL-ova iz instanci `invidio.us` pomoću NewPipe #2488
+• Dodata podrška za URL-ove `music.youtube.com` TeamNewPipe/NewPipeExtractor#194
+
+Ispravljeno
+• [YouTube] Ispravljen 'java.lang.IllegalArgumentException #192
+• [YouTube] Ispravljen prenos uživo koji nije radio TeamNewPipe/NewPipeExtractor#195
+• Ispravljen problem s performansama u android pie-u prilikom preuzimanja prenosa #2592
diff --git a/fastlane/metadata/android/bs/changelogs/790.txt b/fastlane/metadata/android/bs/changelogs/790.txt
new file mode 100644
index 000000000..28ec38810
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/790.txt
@@ -0,0 +1,14 @@
+Poboljšano
+• Dodavanje više naslova radi poboljšanja pristupačnosti za slijepe osobe #2655
+• Učiniti jezik postavki mape za preuzimanje konzistentnijim i manje dvosmislenim #2637
+
+Ispravljeno
+• Provjera da li je posljednji bajt u bloku preuzet #2646
+• Ispravljeno pomicanje u fragmentu detalja videa #2672
+• Uklanjanje dvostrukih animacija okvira za brisanje pretrage u jednu #2695
+• [SoundCloud] Ispravljanje ekstrakcije client_id-a #2745
+
+Razvoj
+• Dodavanje nedostajućih zavisnosti naslijeđenih iz NewPipeExtractor-a u NewPipe #2535
+• Migracija na AndroidX #2685
+• Ažuriranje na ExoPlayer 2.10.6 #2697, #2736
diff --git a/fastlane/metadata/android/bs/changelogs/800.txt b/fastlane/metadata/android/bs/changelogs/800.txt
new file mode 100644
index 000000000..d3f8d5736
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/800.txt
@@ -0,0 +1,27 @@
+Novo
+• Podrška za PeerTube bez P2P-a (#2201) [Beta]:
+◦ Gledajte i preuzimajte videozapise s PeerTube instanci
+◦ Dodajte instance u postavkama za pristup cijelom PeerTube svijetu
+◦ Moguće je da postoje problemi s SSL handshake-ovima na Androidu 4.4 i 7.1 prilikom pristupa određenim instancama, što rezultira mrežnom greškom.
+
+• Downloader (#2679):
+◦ Izračunaj etalon preuzimanja (ETA)
+◦ Preuzmi opus (webm datoteke) kao ogg
+◦ Oporavi istekle linkove za preuzimanje kako bi se nastavilo preuzimanje nakon duge pauze
+
+Poboljšano
+• Učini KioskFragment svjesnim promjena u željenoj zemlji sadržaja i poboljšaj performanse svih glavnih kartica #2742
+• Koristi nove implementacije lokalizacije i downloadera iz ekstraktora #2713
+• Učini niz "Default kiosk" prevodivim
+• Crna navigacijska traka za crnu temu #2569
+
+Ispravljeno
+• Ispravljena greška koja nije mogla pomicati popup player ako je drugi prst postavljen tokom pomicanja popup playera #2772
+• Omogući liste za reprodukciju kojima nedostaje uploader i ispravi padove povezane s ovim problemom #2724, TeamNewPipe/NewPipeExtractor#219
+• Omogući TLS1.1/1.2 na Android 4.4 uređajima (API 19/KitKat) za ispravljanje TLS rukovanja s MediaCCC i nekim PeerTube instance #2792
+• [SoundCloud] Ispravljena ekstrakcija client_id-a TeamNewPipe/NewPipeExtractor #217
+• [SoundCloud] Ispravljena ekstrakcija audio toka
+
+Razvoj
+• Ažuriranje ExoPlayera na 2.10.8 #2791, #2816
+• Ažuriranje Gradlea na 3.5.1 i dodavanje podrške za Kotlin #2714
diff --git a/fastlane/metadata/android/bs/changelogs/810.txt b/fastlane/metadata/android/bs/changelogs/810.txt
new file mode 100644
index 000000000..52d9defbf
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/810.txt
@@ -0,0 +1,20 @@
+Novo
+• Prikaz minijature videa na zaključanom ekranu prilikom reprodukcije u pozadini
+
+Poboljšano
+
+• Dodavanje lokalne liste za reprodukciju u red čekanja prilikom dugog pritiska na dugme za pozadinu / skočni prozor
+• Omogućavanje pomicanja kartica glavne stranice i njihovo skrivanje kada postoji samo jedna kartica
+• Ograničavanje broja ažuriranja minijatura obavještenja u pozadinskom playeru
+• Dodavanje lažne minijature za prazne lokalne liste za reprodukciju
+• Korištenje ekstenzije datoteke *.opus umjesto *.webm i prikaz "opus" u oznaci formata umjesto "WebM Opus" u padajućem izborniku za preuzimanje
+• Dodavanje dugmeta za brisanje preuzetih datoteka ili historije preuzimanja u "Preuzimanja"
+• [YouTube] Dodana podrška za linkove kanala /c/shortened_url
+
+Ispravljeno
+• Ispravljeno više problema prilikom dijeljenja videa na NewPipe i direktnog preuzimanja njegovih tokova
+• Ispravljen pristup playeru izvan teme njegovog kreiranja
+• Ispravljeno podjeljivanje rezultata pretrage
+• [YouTube] Ispravljeno prebacivanje na null što je uzrokovalo NPE
+• [YouTube] Ispravljeno pregledavanje komentara prilikom otvaranja invidio.us URL-a
+• [SoundCloud] Ažuriran client_id
diff --git a/fastlane/metadata/android/bs/changelogs/820.txt b/fastlane/metadata/android/bs/changelogs/820.txt
new file mode 100644
index 000000000..ad9f1a5c2
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/820.txt
@@ -0,0 +1 @@
+Ispravljen je regularni izraz naziva funkcije dešifriranja koji je YouTube činio neupotrebljivim.
diff --git a/fastlane/metadata/android/bs/changelogs/830.txt b/fastlane/metadata/android/bs/changelogs/830.txt
new file mode 100644
index 000000000..b4ba761fe
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/830.txt
@@ -0,0 +1 @@
+Ažuriran je SoundCloud client_id kako bi se riješili problemi sa SoundCloudom.
diff --git a/fastlane/metadata/android/bs/changelogs/840.txt b/fastlane/metadata/android/bs/changelogs/840.txt
new file mode 100644
index 000000000..7820b4d05
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/840.txt
@@ -0,0 +1,22 @@
+Novo
+• Dodan je birač jezika za promjenu jezika aplikacije
+• Dodano je dugme "pošalji na Kodi" u sklopivi meni plejera
+• Dodana je mogućnost kopiranja komentara dugim pritiskom
+
+Poboljšano
+• Ispravljena je ReCaptcha aktivnost i ispravno spremanje dobijenih kolačića
+• Uklonjen je meni s tačkama u korist dugmeta "ladica" i "sakrivanje historije" kada historija gledanja nije omogućena u postavkama
+• Ispravno traženje dozvole za prikaz preko drugih aplikacija u postavkama na Androidu 6 i novijim verzijama
+• Preimenovanje lokalne liste za reprodukciju dugim klikom u BookmarkFragmentu
+• Različita poboljšanja PeerTubea
+• Poboljšano je nekoliko izvornih nizova na engleskom jeziku
+
+Ispravljeno
+• Ispravljeno je ponovno pokretanje plejera iako je pauziran kada je omogućena opcija "minimiziraj pri prebacivanju aplikacija" i NewPipe je minimiziran
+• Ispravljena je početna vrijednost svjetline za gestu
+• Ispravljena su preuzimanja .srt titlova koja nisu sadržavala sve prijelome reda
+• Ispravljeno je neuspješno preuzimanje na SD karticu jer neki Android 5 uređaji nisu kompatibilni sa CTF-om
+• Ispravljeno je preuzimanje na Android KitKat-u
+• Ispravljena je oštećena video .mp4 datoteka koja se prepoznaje kao audio datoteka
+• Ispravljeni su višestruki problemi s lokalizacijom, uključujući pogrešne kineske jezičke kodove
+• [YouTube] Vremenske oznake u opisu su ponovo dostupne za klikanje
diff --git a/fastlane/metadata/android/bs/changelogs/850.txt b/fastlane/metadata/android/bs/changelogs/850.txt
new file mode 100644
index 000000000..4f8c080f9
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/850.txt
@@ -0,0 +1 @@
+U ovom izdanju ažurirana je verzija YouTube web stranice. Stara verzija web stranice bit će ukinuta u martu i stoga je potrebno nadograditi NewPipe.
diff --git a/fastlane/metadata/android/bs/changelogs/860.txt b/fastlane/metadata/android/bs/changelogs/860.txt
new file mode 100644
index 000000000..a2f051bb6
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/860.txt
@@ -0,0 +1,7 @@
+Poboljšano
+• Spremanje i vraćanje bez obzira da li su visina tona i tempo otkačeni ili ne
+• Podrška za izrezivanje ekrana u playeru
+• Kružni prikaz i broj pretplatnika
+• Optimizovan YouTube za korištenje manje podataka
+
+U ovom izdanju ispravljeno je više od 15 grešaka povezanih s YouTubeom.
diff --git a/fastlane/metadata/android/bs/changelogs/870.txt b/fastlane/metadata/android/bs/changelogs/870.txt
new file mode 100644
index 000000000..3706dc130
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/870.txt
@@ -0,0 +1,2 @@
+Ovo je hitna ispravka koja ažurira NewPipe kako bi se ponovo omogućilo korištenje SoundClouda bez većih problema.
+SoundCloudov v2 API se sada koristi u ekstraktoru, a detekcija nevažećih ID-ova klijenata je poboljšana.
diff --git a/fastlane/metadata/android/bs/changelogs/900.txt b/fastlane/metadata/android/bs/changelogs/900.txt
new file mode 100644
index 000000000..c9a2c544d
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/900.txt
@@ -0,0 +1,15 @@
+Novo
+• Grupe pretplata i sortirani feedovi
+• Dugme za isključivanje zvuka u playerima
+
+Poboljšano
+
+• Omogućeno otvaranje linkova music.youtube.com i media.ccc.de u NewPipe-u
+• Premještanje dvije postavke iz Izgled u Sadržaj
+• Sakrivanje opcija pretraživanja od 5, 15, 25 sekundi ako je omogućeno neprecizno pretraživanje
+
+Ispravljeno
+• neki WebM videozapisi se ne mogu pretraživati
+• sigurnosna kopija baze podataka na Android P
+• rušenje prilikom dijeljenja preuzete datoteke
+• mnoštvo problema s ekstrakcijom YouTubea i još mnogo toga ...
diff --git a/fastlane/metadata/android/bs/changelogs/910.txt b/fastlane/metadata/android/bs/changelogs/910.txt
new file mode 100644
index 000000000..d287ea12e
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/910.txt
@@ -0,0 +1 @@
+Ispravljena migracija baze podataka koja je u nekim rijetkim slučajevima sprečavala pokretanje NewPipe-a.
diff --git a/fastlane/metadata/android/bs/changelogs/920.txt b/fastlane/metadata/android/bs/changelogs/920.txt
new file mode 100644
index 000000000..b79042d51
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/920.txt
@@ -0,0 +1,9 @@
+Poboljšano
+
+• Dodan datum otpremanja i broj pregleda za stavke mreže toka
+• Poboljšanja za raspored zaglavlja ladice
+
+Ispravljeno
+
+• Ispravljeno dugme za isključivanje zvuka koje je uzrokovalo pad sistema na API 19
+• Ispravljeno preuzimanje dugih 1080p 60fps videa
diff --git a/fastlane/metadata/android/bs/changelogs/930.txt b/fastlane/metadata/android/bs/changelogs/930.txt
new file mode 100644
index 000000000..3ab5b5d04
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/930.txt
@@ -0,0 +1,20 @@
+Novo
+• Pretraga na YouTube Musicu
+• Osnovna podrška za Android TV
+
+Poboljšano
+
+• Dodana je mogućnost uklanjanja svih gledanih videa s lokalne liste za reprodukciju
+• Prikaz poruke kada sadržaj još nije podržan umjesto rušenja
+• Poboljšana promjena veličine skočnog playera gestama štipanja
+• Stavljanje tokova u red čekanja dugim pritiskom na pozadinu i skočne dugmad u kanalu
+• Poboljšano rukovanje veličinom naslova zaglavlja ladice
+
+Ispravljeno
+• Ispravljena postavka sadržaja s ograničenjem prema dobi koja nije radila
+• Ispravljene određene vrste reCAPTCHA-a
+• Ispravljen pad prilikom otvaranja oznaka dok je lista za reprodukciju `null`
+• Ispravljeno otkrivanje izuzetaka povezanih s mrežom
+• Ispravljena vidljivost dugmeta za sortiranje grupe u fragmentu pretplata
+
+i više
diff --git a/fastlane/metadata/android/bs/changelogs/940.txt b/fastlane/metadata/android/bs/changelogs/940.txt
new file mode 100644
index 000000000..28f0ab256
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/940.txt
@@ -0,0 +1,16 @@
+Novo
+• Dodana podrška za komentare na SoundCloudu
+• Dodana postavka ograničenog načina rada na YouTubeu
+• Prikaz detalja nadređenog kanala na PeerTubeu
+
+Poboljšano
+• Prikaz dugmeta Kore samo za podržane usluge
+• Blokiranje gestova igrača koji počinju na navigacijskoj traci ili statusnoj traci
+• Promjena boje pozadine dugmadi za ponovni pokušaj i pretplatu na osnovu boje usluge
+
+Ispravljeno
+• Ispravljeno zamrzavanje dijaloga za preuzimanje
+• Dugme "Otvori u pregledniku" sada se zaista otvara u pregledniku
+• Ispravljeno rušenje sistema pri otvaranju videa i "Nije moguće reproducirati ovaj tok"
+
+i još mnogo toga
diff --git a/fastlane/metadata/android/bs/changelogs/950.txt b/fastlane/metadata/android/bs/changelogs/950.txt
new file mode 100644
index 000000000..d3dc135a1
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/950.txt
@@ -0,0 +1,4 @@
+Ovo izdanje donosi tri male ispravke:
+• Ispravljen pristup pohrani na Androidu 10+
+• Ispravljeno otvaranje kioska
+• Ispravljeno parsiranje dužih videa
diff --git a/fastlane/metadata/android/bs/changelogs/951.txt b/fastlane/metadata/android/bs/changelogs/951.txt
new file mode 100644
index 000000000..72077d172
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/951.txt
@@ -0,0 +1,17 @@
+Novo
+• Dodan je alat za odabir pretplata u dijalogu grupe feedova
+• Dodan je filter u dijalog grupe feedova kako bi se prikazale samo negrupirane pretplate
+• Dodana je kartica liste za reprodukciju na glavnu stranicu
+• Premotavanje naprijed/nazad u pozadini/u redu čekanja playera
+• Prikaz prijedloga za pretragu: da li ste mislili na & prikaz rezultata za
+
+Poboljšano
+• Izostavljanje metapodataka aplikacije za pisanje u multipliciranim datotekama
+• Ne uklanjanje neuspjelih tokova iz reda čekanja
+• Ažuriranje boje statusne trake da odgovara boji alatne trake
+
+Ispravljeno
+• Ispravljena je desinkronizacija zvuka/videa uzrokovana kumulativnim greškama s pomičnim zarezom
+• [PeerTube] Obrada izbrisanih komentara
+
+i više
diff --git a/fastlane/metadata/android/bs/changelogs/952.txt b/fastlane/metadata/android/bs/changelogs/952.txt
new file mode 100644
index 000000000..9c8b5c617
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/952.txt
@@ -0,0 +1,7 @@
+Poboljšano
+• Automatska reprodukcija je dostupna za sve usluge (umjesto samo za YouTube)
+
+Ispravljeno
+• Ispravljeni povezani tokovi podrškom za nove YouTube nastavke
+• Ispravljeni YouTube videozapisi s ograničenjem za određene uzraste
+• [Android TV] Ispravljeno dugotrajno preklapanje istaknutog fokusa
diff --git a/fastlane/metadata/android/bs/changelogs/953.txt b/fastlane/metadata/android/bs/changelogs/953.txt
new file mode 100644
index 000000000..075e3f47e
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/953.txt
@@ -0,0 +1 @@
+Ispravljena ekstrakcija funkcije dešifriranja na YouTubeu.
diff --git a/fastlane/metadata/android/bs/changelogs/954.txt b/fastlane/metadata/android/bs/changelogs/954.txt
new file mode 100644
index 000000000..7a57794fa
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/954.txt
@@ -0,0 +1,10 @@
+• novi tijek rada aplikacije: reproducirajte videozapise na stranici s detaljima, prevucite prema dolje da biste minimizirali player
+
+• MediaStyle obavještenja: prilagodljive radnje u obavještenjima, poboljšanja performansi
+• osnovna promjena veličine pri korištenju NewPipe-a kao desktop aplikacije
+
+• prikaži dijalog s otvorenim opcijama u slučaju nepodržanog URL tosta
+• Poboljšano iskustvo prijedloga za pretraživanje kada se udaljeni URL-ovi ne mogu dohvatiti
+• Povećan zadani kvalitet videozapisa na 720p60 (player u aplikaciji) i 480p (skočni player)
+
+• mnoštvo ispravki grešaka i još mnogo toga
diff --git a/fastlane/metadata/android/bs/changelogs/955.txt b/fastlane/metadata/android/bs/changelogs/955.txt
new file mode 100644
index 000000000..560aac290
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/955.txt
@@ -0,0 +1,3 @@
+[YouTube] Ispravljena pretraga za neke korisnike
+[YouTube] Ispravljeni izuzeci slučajnog dešifriranja
+[SoundCloud] URL-ovi koji završavaju kosom crtom sada se ispravno parsiraju
diff --git a/fastlane/metadata/android/bs/changelogs/956.txt b/fastlane/metadata/android/bs/changelogs/956.txt
new file mode 100644
index 000000000..b153534eb
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/956.txt
@@ -0,0 +1 @@
+[YouTube] Ispravljen pad aplikacije prilikom učitavanja bilo kojeg videa
diff --git a/fastlane/metadata/android/bs/changelogs/957.txt b/fastlane/metadata/android/bs/changelogs/957.txt
new file mode 100644
index 000000000..9bfe5ddd9
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/957.txt
@@ -0,0 +1,10 @@
+• Ujedinite specifične radnje stavljanja u red u jednu
+• Gesta dva prsta za zatvaranje playera
+• Omogućite brisanje reCAPTCHA kolačića
+• Opcija da se obavještenja ne oboje
+• Poboljšajte način otvaranja detalja videa kako biste riješili beskonačno baferovanje, greške prilikom dijeljenja na NewPipe i druge nedosljednosti
+• Ubrzajte YouTube videozapise i ispravite one s ograničenjem po uzrastu
+• Ispravite pad sistema prilikom premotavanja unaprijed/unazad
+• Nemojte preuređivati liste povlačenjem sličica
+• Uvijek pamtite svojstva skočnih prozora
+• Dodan je santalski jezik
diff --git a/fastlane/metadata/android/bs/changelogs/958.txt b/fastlane/metadata/android/bs/changelogs/958.txt
new file mode 100644
index 000000000..381065d98
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/958.txt
@@ -0,0 +1,15 @@
+Novo i poboljšano:
+• Ponovno dodana opcija za skrivanje sličice na zaključanom ekranu
+• Povlačenje za osvježavanje feeda
+• Poboljšane performanse prilikom preuzimanja lokalnih lista
+
+Ispravljeno:
+• Ispravljen pad sistema prilikom pokretanja NewPipe-a nakon što je uklonjen iz RAM-a
+• Ispravljen pad sistema prilikom pokretanja kada nema internet veze
+• Ispravljeno u vezi s postavkama gestova za svjetlinu i jačinu zvuka
+• [YouTube] Ispravljene duge liste reprodukcije
+
+Ostalo:
+• Čišćenje koda i nekoliko internih poboljšanja
+• Ažuriranja zavisnosti
+• Ažuriranja prevoda
diff --git a/fastlane/metadata/android/bs/changelogs/959.txt b/fastlane/metadata/android/bs/changelogs/959.txt
new file mode 100644
index 000000000..4764f3fea
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/959.txt
@@ -0,0 +1,3 @@
+Ispravljen beskonačan niz rušenja sistema nakon otvaranja izvještaja o greškama.
+Ažurirana lista PeerTube instanci koje NewPipe može automatski otvoriti.
+Ažurirani prijevodi.
diff --git a/fastlane/metadata/android/bs/changelogs/960.txt b/fastlane/metadata/android/bs/changelogs/960.txt
new file mode 100644
index 000000000..8c503be87
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/960.txt
@@ -0,0 +1,3 @@
+• Poboljšan opis opcije izvoza baze podataka u postavkama.
+• Ispravljeno parsiranje komentara na YouTubeu.
+• Ispravljeno ime za prikaz servisa media.ccc.de. • Ažurirani prijevodi.
diff --git a/fastlane/metadata/android/bs/changelogs/961.txt b/fastlane/metadata/android/bs/changelogs/961.txt
new file mode 100644
index 000000000..dfe9db359
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/961.txt
@@ -0,0 +1,12 @@
+• [YouTube] Podrška za Mix
+• [YouTube] Prikaz informacija o javnim emiterima i Covid-19
+• [media.ccc.de] Dodani nedavni videozapisi
+• Dodan prijevod na somalski jezik
+
+• Mnoga interna poboljšanja
+
+• Ispravljeno dijeljenje videozapisa iz playera
+• Ispravljen prazan ReCaptcha web prikaz
+• Ispravljen pad aplikacije koji se javljao prilikom uklanjanja toka s liste
+• [PeerTube] Ispravljeni povezani tokovi
+• [YouTube] Ispravljena pretraga YouTube muzike
diff --git a/fastlane/metadata/android/bs/changelogs/962.txt b/fastlane/metadata/android/bs/changelogs/962.txt
new file mode 100644
index 000000000..72c26f1be
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/962.txt
@@ -0,0 +1,2 @@
+Dodani "nedavni" videozapisi na servis media.ccc.de.
+Dodani su prijenosi uživo na servis media.ccc.de, kao i podrška za prijenos uživo.
diff --git a/fastlane/metadata/android/bs/changelogs/963.txt b/fastlane/metadata/android/bs/changelogs/963.txt
new file mode 100644
index 000000000..1799936e5
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/963.txt
@@ -0,0 +1 @@
+• [YouTube] Ispravljen nastavak kanala
diff --git a/fastlane/metadata/android/bs/changelogs/964.txt b/fastlane/metadata/android/bs/changelogs/964.txt
new file mode 100644
index 000000000..3fd416ae6
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/964.txt
@@ -0,0 +1,8 @@
+• Dodana podrška za poglavlja u kontrolama playera
+• [PeerTube] Dodana pretraga u sepia boji
+• Ponovo dodano dugme za dijeljenje u detaljnom prikazu videa i opis toka premješten u raspored kartica
+• Onemogućeno vraćanje svjetline ako je gesta za svjetlinu onemogućena
+• Dodana stavka liste za reprodukciju videa na Kodiju
+• Ispravljen pad sistema kada na nekim uređajima nije postavljen zadani preglednik i poboljšani su dijalozi za dijeljenje
+• Uključivanje/isključivanje reprodukcije/pauze pomoću hardverskog dugmeta za razmak u playeru preko cijelog ekrana
+• [media.ccc.de] Razne ispravke i poboljšanja
diff --git a/fastlane/metadata/android/bs/changelogs/965.txt b/fastlane/metadata/android/bs/changelogs/965.txt
new file mode 100644
index 000000000..f010b66cb
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/965.txt
@@ -0,0 +1,6 @@
+Ispravljen pad sistema koji se javljao prilikom promjene redoslijeda grupa kanala.
+Ispravljeno dobijanje više YouTube videa sa kanala i plejlista.
+Ispravljeno dobijanje YouTube komentara.
+Dodana je podrška za podputanje /watch/, /v/ i /w/ u YouTube URL-ovima.
+Ispravljeno izdvajanje SoundCloud klijentskog ID-a i geo-ograničenog sadržaja.
+Dodana je lokalizacija za sjeverni kurdski jezik.
diff --git a/fastlane/metadata/android/bs/changelogs/966.txt b/fastlane/metadata/android/bs/changelogs/966.txt
new file mode 100644
index 000000000..7f47d9ac9
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/966.txt
@@ -0,0 +1,14 @@
+Novo:
+• Dodana nova usluga: Bandcamp
+
+Poboljšano:
+• Dodana opcija da aplikacija prati temu uređaja
+• Spriječeni su neki rušenji prikazivanjem poboljšane ploče s greškama
+• Prikaz više informacija o tome zašto sadržaj nije dostupan
+• Dugme za razmak na hardveru pokreće reprodukciju/pauzu
+• Prikaz tosta "Preuzimanje započeto"
+
+Ispravljeno:
+• Ispravljena je vrlo mala sličica u detaljima videa tokom reprodukcije u pozadini
+• Ispravljen je prazan naslov u minimiziranom playeru
+• Ispravljena je greška zbog koje se posljednji način promjene veličine nije ispravno vraćao
diff --git a/fastlane/metadata/android/bs/changelogs/967.txt b/fastlane/metadata/android/bs/changelogs/967.txt
new file mode 100644
index 000000000..039051547
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/967.txt
@@ -0,0 +1 @@
+Ispravljen je problem sa neispravnim radom YouTubea u EU. Uzrok tome je bio novi sistem za pristanak na kolačiće i privatnost koji zahtijeva da NewPipe postavi kolačić PRISTANAK.
diff --git a/fastlane/metadata/android/bs/changelogs/968.txt b/fastlane/metadata/android/bs/changelogs/968.txt
new file mode 100644
index 000000000..d7e5be7b4
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/968.txt
@@ -0,0 +1,7 @@
+Dodana je opcija za detalje kanala u meni s dugim pritiskom.
+Dodana je funkcionalnost preimenovanja naziva liste za reprodukciju iz sučelja liste za reprodukciju.
+Omogućeno korisniku pauziranje dok se video učitava.
+Dotjerana je bijela tema.
+Ispravljeno preklapanje fontova pri korištenju veće veličine fonta.
+Ispravljen je problem s nedostatkom videa na Formuler i Zephier uređajima.
+Ispravljeni su razni padovi sistema.
diff --git a/fastlane/metadata/android/bs/changelogs/969.txt b/fastlane/metadata/android/bs/changelogs/969.txt
new file mode 100644
index 000000000..804873f1e
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/969.txt
@@ -0,0 +1,8 @@
+• Dozvoljena instalacija na eksternu memoriju
+• [Bandcamp] Dodata podrška za prikaz prva tri komentara na toku
+• Prikaži samo obavijest 'preuzimanje je počelo' kada je preuzimanje pokrenuto
+• Ne postavljaj reCaptcha kolačić kada nema pohranjenih kolačića
+• [Player] Poboljšane performanse keša
+• [Player] Ispravljena greška u reprodukciji u plejeru
+• Odbaci prethodne Snackbarove prilikom brisanja preuzimanja
+• Ispravljen pokušaj brisanja objekta koji nije na listi
diff --git a/fastlane/metadata/android/bs/changelogs/970.txt b/fastlane/metadata/android/bs/changelogs/970.txt
new file mode 100644
index 000000000..414f6c9c6
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/970.txt
@@ -0,0 +1,11 @@
+Novo
+• Prikaz metapodataka sadržaja (oznake, kategorije, licenca, ...) ispod opisa
+• Dodana opcija "Prikaži detalje kanala" u udaljenim (nelokalnim) listama za reprodukciju
+• Dodana opcija "Otvori u pregledniku" u meni s dugim pritiskom
+
+Ispravljeno
+• Ispravljen pad sistema prilikom rotacije na stranici s detaljima videa
+• Ispravljeno dugme "Reproduciraj s Kodijem" u playeru koje uvijek traži instalaciju Kore-a
+• Ispravljeno i poboljšano podešavanje putanja uvoza i izvoza
+• [YouTube] Ispravljen broj lajkova za komentare
+I još mnogo toga
diff --git a/fastlane/metadata/android/bs/changelogs/971.txt b/fastlane/metadata/android/bs/changelogs/971.txt
new file mode 100644
index 000000000..f49116929
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/971.txt
@@ -0,0 +1,3 @@
+Hitna ispravka
+• Povećanje bafera za reprodukciju nakon ponovnog baferovanja
+• Ispravljen pad sistema na tabletima i televizorima prilikom klika na ikonu reda za reprodukciju u plejeru
diff --git a/fastlane/metadata/android/bs/changelogs/972.txt b/fastlane/metadata/android/bs/changelogs/972.txt
new file mode 100644
index 000000000..e422201cf
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/972.txt
@@ -0,0 +1,14 @@
+Novo
+Prepoznavanje vremenskih oznaka i hashtagova u opisu
+Dodano ručno podešavanje tablet režima
+Dodana mogućnost skrivanja reprodukovanih stavki u feedu
+
+Poboljšano
+Ispravno podržavanje okvira za pristup pohrani
+Bolje rukovanje greškama nedostupnih i prekinutih kanala
+Android tabela za dijeljenje za korisnike Androida 10+ sada prikazuje naslov sadržaja.
+Ažurirane su Invidious instance i podrška za preusmjerene linkove.
+
+Ispravljeno
+[YouTube] Sadržaj ograničen prema dobi
+Spriječen izuzetak curenja prozora prilikom otvaranja dijaloga za izbor
diff --git a/fastlane/metadata/android/bs/changelogs/973.txt b/fastlane/metadata/android/bs/changelogs/973.txt
new file mode 100644
index 000000000..0e78a352e
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/973.txt
@@ -0,0 +1,4 @@
+Hitna ispravka
+• Ispravljene sličice i naslovi koji su se skraćivali u rasporedu mreže, zbog pogrešnog izračuna koliko videozapisa može stati u jedan red
+• Ispravljen dijalog za preuzimanje koji je nestajao bez ikakve radnje ako se otvori iz menija za dijeljenje
+• Ažurirana biblioteka povezana s otvaranjem vanjskih aktivnosti kao što je birač datoteka Storage Access Frameworka
diff --git a/fastlane/metadata/android/bs/changelogs/974.txt b/fastlane/metadata/android/bs/changelogs/974.txt
new file mode 100644
index 000000000..991a16e09
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/974.txt
@@ -0,0 +1,5 @@
+Hitna ispravka
+• Ispravljeni problemi s baferovanjem uzrokovani ograničavanjem YouTubea
+• Ispravljeno izdvajanje komentara na YouTubeu i rušenja aplikacije s onemogućenim komentarima
+• Ispravljena pretraga muzike na YouTubeu
+• Ispravljeni prenosi uživo na PeerTubeu
diff --git a/fastlane/metadata/android/bs/changelogs/975.txt b/fastlane/metadata/android/bs/changelogs/975.txt
new file mode 100644
index 000000000..ab5edb692
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/975.txt
@@ -0,0 +1,17 @@
+Novo
+• Prikaz pregleda sličice tokom pretraživanja
+• Detekcija onemogućenih komentara
+• Omogućeno označavanje stavke feeda kao gledane
+• Prikaz srca u komentarima
+
+Poboljšano
+• Poboljšan raspored metapodataka i oznaka
+• Primjena boje usluge na UI komponente
+
+Ispravljeno
+• Ispravljena sličica u mini playeru
+• Ispravljeno beskonačno baferovanje duplih stavki reda čekanja
+• Neke ispravke playera poput rotacije i bržeg zatvaranja
+• Ispravljena ReCAPTCHA koja ostaje učitana u pozadini
+• Onemogući klikove prilikom osvježavanja feeda
+• Ispravljeni neki padovi preuzimanja
diff --git a/fastlane/metadata/android/bs/changelogs/976.txt b/fastlane/metadata/android/bs/changelogs/976.txt
new file mode 100644
index 000000000..86abfacf2
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/976.txt
@@ -0,0 +1,10 @@
+• Dodana je opcija za direktno otvaranje playera preko cijelog ekrana
+• Omogućen je odabir vrsta prijedloga za pretragu koji će se prikazivati
+• Tamna tema je sada tamnija + dodan je tamniji početni ekran
+• Poboljšan birač datoteka za sivo označavanje neželjenih datoteka
+• Ispravljen uvoz YouTube pretplata
+• Ponovna reprodukcija toka zahtijeva ponovni dodir dugmeta za reprodukciju
+• Ispravljeno zatvaranje audio sesije
+• [Android TV] Ispravljeni su dugi skokovi na traci za pretraživanje prilikom korištenja DPad-a
+
+Da biste vidjeli daljnje promjene, pogledajte dnevnik promjena (i objavu na blogu) na kartici Linkovi ispod.
diff --git a/fastlane/metadata/android/bs/changelogs/977.txt b/fastlane/metadata/android/bs/changelogs/977.txt
new file mode 100644
index 000000000..da79b791f
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/977.txt
@@ -0,0 +1,10 @@
+• Dodano dugme "reproduciraj sljedeće" u meni dugog pritiska
+• Dodan prefiks putanje YouTube kratkih videozapisa u filter namjere
+• Ispravljen uvoz postavki
+• Zamjena pozicije trake za pretraživanje s dugmadima playera na ekranu reda čekanja
+• Razne ispravke vezane za MediasessionManager
+• Ispravljena traka za pretraživanje koja se nije dovršila nakon završetka videa
+• Onemogućeno tuneliranje medija na RealtekATV-u
+• Prošireno područje za klik na minimizirana dugmad playera
+
+Da biste vidjeli daljnje promjene, pogledajte dnevnik promjena (i objavu na blogu) na kartici Linkovi ispod.
diff --git a/fastlane/metadata/android/bs/changelogs/978.txt b/fastlane/metadata/android/bs/changelogs/978.txt
new file mode 100644
index 000000000..132fa5cd4
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/978.txt
@@ -0,0 +1 @@
+Ispravljeno izvršavanje provjere za novu verziju NewPipe-a. Ova provjera se ponekad izvršavala prerano i stoga je dovodila do pada aplikacije. To bi sada trebalo biti ispravljeno.
diff --git a/fastlane/metadata/android/bs/changelogs/979.txt b/fastlane/metadata/android/bs/changelogs/979.txt
new file mode 100644
index 000000000..50a39f3c7
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/979.txt
@@ -0,0 +1,2 @@
+- Ispravljeno nastavljanje reprodukcije
+- Poboljšanja kako bi se osiguralo da servis koji određuje da li NewPipe treba provjeravati nove verzije nije pokrenut u pozadini
diff --git a/fastlane/metadata/android/bs/changelogs/980.txt b/fastlane/metadata/android/bs/changelogs/980.txt
new file mode 100644
index 000000000..58fe99af8
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/980.txt
@@ -0,0 +1,13 @@
+Novo
+• Dodana je opcija "Dodaj na listu za reprodukciju" u meni za dijeljenje
+• Dodana je podrška za kratke linkove na y2u.be i PeerTube
+
+Poboljšano
+• Kontrole brzine reprodukcije su kompaktnije
+• Feed sada ističe nove stavke
+• Opcija "Prikaži gledane stavke" u feedu je sada sačuvana
+
+Ispravljeno
+• Ispravljeno izdvajanje lajkova i nesviđanja na YouTubeu
+• Ispravljena je automatska reprodukcija nakon povratka iz pozadine
+I još mnogo toga
diff --git a/fastlane/metadata/android/bs/changelogs/981.txt b/fastlane/metadata/android/bs/changelogs/981.txt
new file mode 100644
index 000000000..d832a5ba0
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/981.txt
@@ -0,0 +1,2 @@
+Uklonjena je podrška za MediaParser kako bi se riješio problem neuspjelog nastavka reprodukcije nakon baferovanja na Androidu 11+.
+Onemogućeno je tuneliranje medija na Philips QM16XE uređaju kako bi se riješili problemi s reprodukcijom.
diff --git a/fastlane/metadata/android/bs/changelogs/982.txt b/fastlane/metadata/android/bs/changelogs/982.txt
new file mode 100644
index 000000000..39ccdd3e6
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/982.txt
@@ -0,0 +1 @@
+Ispravljena greška zbog koje YouTube nije reprodukovao nijedan tok.
diff --git a/fastlane/metadata/android/bs/changelogs/983.txt b/fastlane/metadata/android/bs/changelogs/983.txt
new file mode 100644
index 000000000..ebf3841e1
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/983.txt
@@ -0,0 +1,9 @@
+Dodati novi korisnički interfejs i ponašanje za pretraživanje dvostrukim dodirom
+Omogućiti pretraživanje postavki
+Istaknuti zakačene komentare kao takve
+Dodati podršku za otvaranje s aplikacijom za FSFE-ovu PeerTube instancu
+Dodati obavještenja o greškama
+Ispraviti ponavljanje prve stavke reda čekanja pri promjeni igrača
+Duže čekati prilikom učitavanja u međuspremniku tokom prijenosa uživo prije nego što dođe do greške
+Ispraviti redoslijed lokalnih rezultata pretrage
+Ispraviti prazna polja stavki u redu čekanja za reprodukciju
diff --git a/fastlane/metadata/android/bs/changelogs/984.txt b/fastlane/metadata/android/bs/changelogs/984.txt
new file mode 100644
index 000000000..300013d5e
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/984.txt
@@ -0,0 +1,7 @@
+Učitajte dovoljno početnih stavki u listama da popune cijeli ekran i da se riješi problem skrolovanja na tabletima i televizorima
+Ispravite nasumična rušenja prilikom skrolovanja kroz liste
+Neka se luk preklapanja brzog pretraživanja plejera nalazi ispod sistemskog korisničkog interfejsa
+Vratite promjene izreza prilikom reprodukcije u više prozora, što je uzrokovalo regresiju pogrešno postavljenog plejera na nekim telefonima
+Povećajte compileSdk sa 30 na 31
+Ažurirajte biblioteku za prijavljivanje grešaka
+Refaktorišite dio koda u plejeru
diff --git a/fastlane/metadata/android/bs/changelogs/985.txt b/fastlane/metadata/android/bs/changelogs/985.txt
new file mode 100644
index 000000000..acd29e47c
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/985.txt
@@ -0,0 +1 @@
+Ispravljeno je da YouTube ne reprodukuje nijedan tok
diff --git a/fastlane/metadata/android/bs/changelogs/986.txt b/fastlane/metadata/android/bs/changelogs/986.txt
new file mode 100644
index 000000000..f7a82bf00
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/986.txt
@@ -0,0 +1,17 @@
+Novo
+• Obavještenja za nove tokove
+• Besprijekoran prijelaz između pozadinskog i video playera
+• Promjena visine tona za polutone
+• Dodavanje reda čekanja glavnog playera na listu za reprodukciju
+
+Poboljšano
+
+• Zapamti brzinu/veličinu koraka visine tona
+• Ublaži početno dugo baferovanje u video playeru
+• Poboljšan korisnički interfejs playera za Android TV
+• Potvrdi prije brisanja svih preuzetih datoteka
+
+Ispravljeno
+• Ispravljeno dugme za medije koje nije skrivalo kontrole playera
+• Ispravljeno resetovanje reprodukcije pri promjeni tipa playera
+• Ispravljeno rotiranje dijaloga liste za reprodukciju
diff --git a/fastlane/metadata/android/bs/changelogs/987.txt b/fastlane/metadata/android/bs/changelogs/987.txt
new file mode 100644
index 000000000..d14bfa7ee
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/987.txt
@@ -0,0 +1,12 @@
+Novo
+• Podrška za metode isporuke osim progresivnog HTTP-a: brže vrijeme učitavanja reprodukcije, ispravke za PeerTube i SoundCloud, reprodukcija nedavno završenih YouTube prijenosa uživo
+• Dodano dugme za dodavanje udaljene liste za reprodukciju na lokalnu
+• Pregled slike u Android 10+ listu za dijeljenje
+
+Poboljšano
+• Poboljšan dijalog parametara reprodukcije
+• Dugmad za uvoz/izvoz pretplate premještena u meni s tri tačke
+
+Ispravljeno
+• Ispravljeno uklanjanje potpuno pregledanih videozapisa s liste za reprodukciju
+• Ispravljena tema menija za dijeljenje i unos "dodaj na listu za reprodukciju"
diff --git a/fastlane/metadata/android/bs/changelogs/988.txt b/fastlane/metadata/android/bs/changelogs/988.txt
new file mode 100644
index 000000000..fa0f905ba
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/988.txt
@@ -0,0 +1,2 @@
+[YouTube] Ispravljena greška "Nije moguće dobiti tok" prilikom pokušaja reprodukcije bilo kojeg videa
+[YouTube] Ispravljena poruka "Sljedeći sadržaj nije dostupan u ovoj aplikaciji" koja se prikazuje umjesto traženog videa
diff --git a/fastlane/metadata/android/bs/changelogs/989.txt b/fastlane/metadata/android/bs/changelogs/989.txt
new file mode 100644
index 000000000..6c80f717e
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/989.txt
@@ -0,0 +1,3 @@
+• [YouTube] Ispravljeno beskonačno učitavanje pri pokušaju reprodukcije bilo kojeg videa
+• [YouTube] Ispravljeno ograničavanje reprodukcije nekih videa
+• Nadogradite biblioteku jsoup na verziju 1.15.3, što uključuje sigurnosnu ispravku
diff --git a/fastlane/metadata/android/bs/changelogs/990.txt b/fastlane/metadata/android/bs/changelogs/990.txt
new file mode 100644
index 000000000..49f7ffe95
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/990.txt
@@ -0,0 +1,15 @@
+Ovo izdanje ukida podršku za Android 4.4 KitKat, sada je minimalna verzija Android 5 Lollipop!
+
+Novo
+• Preuzimanje iz menija s dugim pritiskom
+• Skrivanje budućih videa u feedu
+• Dijeljenje lokalnih lista za reprodukciju
+
+Poboljšano
+• Refaktorisanje koda playera u male komponente: manje RAM-a se koristi, manje grešaka
+• Poboljšan način skaliranja sličica
+• Vektorska konverzija rezerviranih mjesta za slike
+
+Ispravljeno
+• Ispravljeni razni problemi s obavještenjima playera: zastarjele/nedostajuće informacije o medijima, iskrivljena sličica
+• Ispravljen prikaz preko cijelog ekrana koristeći 1/4 ekrana
diff --git a/fastlane/metadata/android/bs/changelogs/991.txt b/fastlane/metadata/android/bs/changelogs/991.txt
new file mode 100644
index 000000000..bdbb7a5b7
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/991.txt
@@ -0,0 +1,14 @@
+Novo
+• Dodano dugme "Otvori u pregledniku" u panelu s greškama
+• Dodana opcija za prikaz grupa kanala kao liste
+• [YouTube] Dugi klik na segmente toka za dijeljenje URL-a vremenske oznake
+• Dodano dugme za red čekanja za reprodukciju u mini player
+
+Poboljšano
+
+• Dodana lokalizacija za islandski jezik i ažurirani mnogi drugi prijevodi
+• Mnoga interna poboljšanja
+
+Ispravljeno
+• Ispravljeno višestruko rušenje sistema
+• [YouTube] Ispravljeno učitavanje kanala, nenamjenski feed i zaobilazno rješenje problema s reprodukcijom u nekim zemljama
diff --git a/fastlane/metadata/android/bs/changelogs/992.txt b/fastlane/metadata/android/bs/changelogs/992.txt
new file mode 100644
index 000000000..f101f68f0
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/992.txt
@@ -0,0 +1,17 @@
+Novo
+• Broj pretplatnika u detaljima videa
+• Preuzimanje iz reda čekanja
+• Trajno postavljanje sličice liste za reprodukciju
+• Dugi pritisak na hashtagove i linkove
+• Način prikaza kartice
+
+Poboljšano
+• Veće dugme za zatvaranje mini-playera
+• Glatko smanjenje sličica
+• Ciljano za Android 13 (API 33)
+• Traženje više ne pauzira player
+
+Ispravljeno
+• Ispravljen prekrivač na DeX-u/mišu
+• Omogućen pozadinski player bez odvojenih audio tokova
+• Razne ispravke za YouTube i još mnogo toga…
diff --git a/fastlane/metadata/android/bs/changelogs/993.txt b/fastlane/metadata/android/bs/changelogs/993.txt
new file mode 100644
index 000000000..4677738e9
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/993.txt
@@ -0,0 +1,12 @@
+Novo
+• Dodano upozorenje prilikom dodavanja duplikata liste za reprodukciju i dodavanje dugmeta za njihovo uklanjanje
+• Omogućeno ignorisanje hardverskih dugmadi
+• Omogućeno skrivanje djelomično pregledanih videa u feedu
+
+Poboljšano
+• Koristiti više kolona mreže na velikim ekranima
+• Usaglasiti indikatore napretka s postavkama
+
+Ispravljeno
+• Ispravljeno otvaranje URL-ova preglednika, preuzimanja i vanjskih playera na Androidu 11+
+• Ispravljena interakcija s cijelim ekranom koja zahtijeva dva dodira na MIUI-ju
diff --git a/fastlane/metadata/android/bs/changelogs/994.txt b/fastlane/metadata/android/bs/changelogs/994.txt
new file mode 100644
index 000000000..0440a2c94
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/994.txt
@@ -0,0 +1,15 @@
+Novo
+• Podrška za više audio zapisa/jezika
+• Omogućeno podešavanje jačine zvuka i svjetline gestama sa bilo koje strane ekrana
+• Podrška za prikaz glavnih kartica na dnu ekrana
+
+Poboljšano
+• [Bandcamp] Rukovanje zapisima iza paywalla
+
+Ispravljeno
+• [YouTube] 403 HTTP greške za tokove
+• Crni plejer pri prelasku na glavni plejer sa prikaza liste za reprodukciju
+• Curenje memorije servisa plejera
+• [PeerTube] Avatari za uploader i podkanal su zamijenjeni
+
+i više
diff --git a/fastlane/metadata/android/bs/changelogs/995.txt b/fastlane/metadata/android/bs/changelogs/995.txt
new file mode 100644
index 000000000..68912e20d
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/995.txt
@@ -0,0 +1,16 @@
+Novo
+• Podrška za kartice kanala
+• Odabir kvalitete slike
+• Dobijanje URL-ova za sve slike
+
+Poboljšano
+• Pristupačnost interfejsa playera
+• Bolji odabir zvuka za preuzimanja samo videozapisa
+• Opcija za uključivanje naziva popisa za reprodukciju i videozapisa u dijeljeni sadržaj popisa za reprodukciju
+
+Ispravljeno
+• [YouTube] Ispravljeno dobijanje broja lajkova
+• Ispravljeni skočni prozori i padovi sustava koji ne reagiraju na player
+• Odabir pogrešnih jezika u biraču jezika
+• Fokus zvuka playera nije poštovao zvuk
+• Dodavanje stavki popisa za reprodukciju povremeno nije radilo
diff --git a/fastlane/metadata/android/bs/changelogs/996.txt b/fastlane/metadata/android/bs/changelogs/996.txt
new file mode 100644
index 000000000..0fa343ba2
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/996.txt
@@ -0,0 +1,2 @@
+Ispravljen je NullPointerException prilikom otvaranja kanala/konferencije u media.ccc.de.
+Grinch je pokušao da vam pokvari naš božićni poklon, ali smo ga ispravili.
diff --git a/fastlane/metadata/android/bs/changelogs/997.txt b/fastlane/metadata/android/bs/changelogs/997.txt
new file mode 100644
index 000000000..1703a1f7c
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/997.txt
@@ -0,0 +1,17 @@
+Novo
+• Dodajte odgovore na komentare
+• Omogućite promjenu redoslijeda lista za reprodukciju
+• Prikažite opis i trajanje liste za reprodukciju
+• Omogućite resetiranje postavki
+
+Poboljšano
+• [Android 13+] Vratite prilagođene radnje obavještenja
+• Zatražite saglasnost za provjeru ažuriranja
+• Omogućite reprodukciju/pauziranje obavještenja tokom učitavanja u međuspremnik
+• Promijenite redoslijed nekih postavki
+
+Ispravljeno
+• [YouTube] Ispravljen komentari koji se ne učitavaju, plus druge ispravke i poboljšanja
+• Rješite ranjivost u uvozu postavki i prebacite se na JSON
+• Razne ispravke preuzimanja
+• Skratite tekst pretrage
diff --git a/fastlane/metadata/android/bs/changelogs/998.txt b/fastlane/metadata/android/bs/changelogs/998.txt
new file mode 100644
index 000000000..6a8cecc00
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/998.txt
@@ -0,0 +1,4 @@
+Ispravljena greška zbog koje YouTube nije reproducirao nijedan tok zbog HTTP 403 greške.
+
+Povremene HTTP 403 greške usred YouTube videa još nisu ispravljene.
+Taj problem će biti riješen u drugom izdanju hitne ispravke što je prije moguće.
diff --git a/fastlane/metadata/android/bs/changelogs/999.txt b/fastlane/metadata/android/bs/changelogs/999.txt
new file mode 100644
index 000000000..864bf68ec
--- /dev/null
+++ b/fastlane/metadata/android/bs/changelogs/999.txt
@@ -0,0 +1,12 @@
+Ovo izdanje hitne ispravke ispravlja HTTP 403 greške usred YouTube videa.
+
+Novo
+• [SoundCloud] Dodata podrška za on.soundcloud.com URL-ove
+
+Poboljšano
+• [Bandcamp] Prikaz dodatnih informacija u radio kiosku
+
+Ispravljeno
+• [YouTube] Ispravljene povremene HTTP 403 greške na početku ili usred videa
+• [YouTube] Izdvajanje avatara i banera iz više tipova zaglavlja kanala
+• [Bandcamp] Ispravljene razne greške i uvijek korištenje HTTPS-a
diff --git a/fastlane/metadata/android/cs/changelogs/1005.txt b/fastlane/metadata/android/cs/changelogs/1005.txt
index 2059e43de..e8efaffad 100644
--- a/fastlane/metadata/android/cs/changelogs/1005.txt
+++ b/fastlane/metadata/android/cs/changelogs/1005.txt
@@ -1,17 +1,17 @@
-Novinky
-• Přidána podpora pro Android Auto.
-• Možnost nastavit skupiny kanálů jako záložky na hlavní obrazovce.
-• [YouTube] Sdílení jako dočasný seznam skladeb.
-• [SoundCloud] Záložka Oblíbené kanály
+Nově
+• Podpora pro Android Auto
+• Možnost nastavit skupiny zdrojů jako záložky
+• [YouTube] Sdílení jako dočasný playlist
+• [SoundCloud] Záložka Oblíbené u kanálů
Vylepšeno
-• Lepší nápověda pro vyhledávací lištu
-• Zobrazení data stažení v sekci Stažené soubory
-• Použití jazyka Android 13 pro jednotlivé aplikace
+• Lepší našeptávač vyhledávače
+• Zobrazení data stažení ve Stažených
+• Použití individuálního jazyka
Opraveno
• Oprava chybných barev textu v tmavém režimu
-• [YouTube] Oprava seznamů skladeb, které nenačtou více než 100 položek
+• [YouTube] Oprava nenačtení více než 100 položek v playlistech
• [YouTube] Oprava chybějících doporučených videí
-• Oprava pádů v zobrazení seznamu historie
-• Oprava časových značek v odpovědích na komentáře
+• Oprava pádů v Historii
+• Oprava časů v odpovědích
diff --git a/fastlane/metadata/android/cs/changelogs/1006.txt b/fastlane/metadata/android/cs/changelogs/1006.txt
new file mode 100644
index 000000000..88c312e14
--- /dev/null
+++ b/fastlane/metadata/android/cs/changelogs/1006.txt
@@ -0,0 +1,12 @@
+# Vylepšení
+Ponechání aktuálního přehrávače při klepnutí na časová razítka
+Pokus o obnovení čekajících stahování, pokud to jde
+Možnost odstranění stahování bez smazání souboru
+Oprávnění Zobrazení přes ostatní aplikace: zobrazení vysvětlení pro Android > R
+Podpora odkazů on.soundcloud
+
+# Opravy
+Oprava formátování pro verze Androidu nižší než 7
+Oprava falešných oznámení
+Opravy souborů titulků SRT
+Oprava spousty pádů
diff --git a/fastlane/metadata/android/de/changelogs/1002.txt b/fastlane/metadata/android/de/changelogs/1002.txt
index 6c6dc761a..23be04e80 100644
--- a/fastlane/metadata/android/de/changelogs/1002.txt
+++ b/fastlane/metadata/android/de/changelogs/1002.txt
@@ -1,4 +1,4 @@
Behoben: YouTube spielt keinen Stream ab.
-Diese Version behebt nur den dringendsten Fehler, der das Laden von YouTube-Videodetails verhindert.
+Diese Version behebt nur den dringenden Fehler, der das Laden von YouTube-Videodetails verhindert.
Wir sind uns bewusst, dass es andere Probleme gibt, und wir werden bald eine separate Version erstellen, um sie zu lösen.
diff --git a/fastlane/metadata/android/de/changelogs/1006.txt b/fastlane/metadata/android/de/changelogs/1006.txt
new file mode 100644
index 000000000..1a76b6f0e
--- /dev/null
+++ b/fastlane/metadata/android/de/changelogs/1006.txt
@@ -0,0 +1,13 @@
+# Verbesserungen
+Aktuellen Player beim Klick auf Zeitstempel beibehalten
+Wiederherstellen ausstehender Downloadaufträge
+Downloads löschen, ohne gleichzeitiges Löschen der Datei
+Overlay-Berechtigung: Erklärendes Dialogfeld für Android > R
+Unterstützung von on.soundcloud-Links
+Viele kleine Verbesserungen und Optimierungen
+
+# Behoben
+Kurzformatierung für Android-Versionen unter 7
+Geisterbenachrichtigungen
+SRT-Untertiteldateien
+Zahlreiche Abstürze
diff --git a/fastlane/metadata/android/de/changelogs/63.txt b/fastlane/metadata/android/de/changelogs/63.txt
index 3ccc56bc0..7ae7873fb 100644
--- a/fastlane/metadata/android/de/changelogs/63.txt
+++ b/fastlane/metadata/android/de/changelogs/63.txt
@@ -4,5 +4,5 @@
- Kleine Codeverbesserungen #1375
- Alles über DSGVO hinzugefügt #1420
-### Repariert
+### Behoben
- Downloader: Absturz beim Laden unvollendeter Downloads von .giga-Dateien behoben #1407
diff --git a/fastlane/metadata/android/de/changelogs/68.txt b/fastlane/metadata/android/de/changelogs/68.txt
index f700b3d26..9d37a92fc 100644
--- a/fastlane/metadata/android/de/changelogs/68.txt
+++ b/fastlane/metadata/android/de/changelogs/68.txt
@@ -1,12 +1,12 @@
# Änderungen von v0.14.1
-### Fixed
+### Behoben
- nicht entschlüsselt Video url #1659
- Beschreibungs Link nicht extrahierbar #1657
# Änderungen von v0.14.0
-### New
+### Neu
- Neues Schubladendesign #1461
- Neue anpassbare Titelseite #1461
@@ -14,6 +14,6 @@
- Reworked Gesture Controls #1604
- Neue Möglichkeit, den Pop-up-Player #1597 zu schließen
-### Fixed
+### Behoben
- Fehler beheben, wenn die Anzahl der Abonnements nicht verfügbar ist. Schließt #1649.
- Zeigen Sie "Abonnentenzählung nicht verfügbar" in diesen Fällen.
diff --git a/fastlane/metadata/android/de/changelogs/69.txt b/fastlane/metadata/android/de/changelogs/69.txt
index 8802508a3..3e8cb3a6e 100644
--- a/fastlane/metadata/android/de/changelogs/69.txt
+++ b/fastlane/metadata/android/de/changelogs/69.txt
@@ -1,14 +1,15 @@
-### New
-- Long-tap Löschen & Teilen in Abonnements #1516
-- Tablet UI & Rasterlistenlayout #1617
+### Neu
+- Langes Tippen zum Löschen/Teilen in Abonnements #1516
+- Tablet-UI und Rasterlistenlayout #1617
### Verbesserungen
-- Speichern und Nachladen des zuletzt verwendeten Seitenverhältnisses #1748
-- Separate Einstellungen für Lautstärke & Helligkeitsgesten #1644
+- Speichern/Neuladen des zuletzt verwendeten Seitenverhältnisses #1748
+- Separate Einstellungen für Lautstärke-/Helligkeitsgesten #1644
+- Unterstützung für Lokalisierung #1792
-### Fixes
+### Fehlerbehebungen
- Anzahl der Abonnements
-- Foreground Service Erlaubnis für API 28+ Geräte #1830 hinzugefügt
+- Vordergrund-Dienstberechtigung für Geräte mit API 28+ hinzugefügt #1830
-### Known Bugs
-- Wiedergabe kann nicht auf Android P gespeichert werden
+### Bekannte Fehler
+- Wiedergabestatus wird unter Android P nicht gespeichert
diff --git a/fastlane/metadata/android/de/changelogs/70.txt b/fastlane/metadata/android/de/changelogs/70.txt
index 59a09b210..b31f83720 100644
--- a/fastlane/metadata/android/de/changelogs/70.txt
+++ b/fastlane/metadata/android/de/changelogs/70.txt
@@ -5,6 +5,6 @@ ACHTUNG: Diese Version ist wahrscheinlich ein Bugfest.
* Drop-Unterstützung für Android 4.1 - 4.3 #1884
* Streams aus der aktuellen Warteschlange entfernt, indem sie nach rechts swipen #1915
-### Fixed
+### Behoben
* Crash mit Standard-Auflösung eingestellt auf beste und begrenzte mobile Datenauflösung #1835
* Pop-up-Spieler-Absturz behoben #1874
diff --git a/fastlane/metadata/android/de/changelogs/71.txt b/fastlane/metadata/android/de/changelogs/71.txt
index 0132de3c3..86d1d52d9 100644
--- a/fastlane/metadata/android/de/changelogs/71.txt
+++ b/fastlane/metadata/android/de/changelogs/71.txt
@@ -1,8 +1,10 @@
### Verbesserungen
-* App-Update-Benachrichtigung für GitHub build hinzufügen (#1608 von @krtkush)
-* Verschiedene Verbesserungen des Downloaders (#1944 von @kapodamy):
-* Fügen Sie fehlende weiße Icons hinzu und verwenden Sie hardcored Weg, um die Icon Farben zu ändern
-* neue MPEG-4 muxer fixieren nicht-synchrone Video- und Audiostreams (#2039)
+* Benachrichtigung über App-Updates für GitHub-Build (#1608 von @krtkush)
+* Verschiedene Verbesserungen am Downloader (#1944 von @kapodamy):
+ * Weiße Symbole und Hardcoded-Methode zum Ändern der Symbolfarben
+ * Überprüfung, ob der Iterator initialisiert ist (behebt #2031)
+ * Erlaubt erneute Downloads mit dem Fehler „Nachbearbeitung fehlgeschlagen“ im neuen Muxer
+ * Neuer MPEG-4-Muxer (#2039)
-### Fixed
-* YouTube Live-Streams spielen nach kurzer Zeit (#1996 von @yausername)
+### Behoben
+* YouTube-Livestreams werden nicht abgespielt (#1996 von @yausername)
diff --git a/fastlane/metadata/android/de/changelogs/730.txt b/fastlane/metadata/android/de/changelogs/730.txt
index 12c5ffb16..dc534fea2 100644
--- a/fastlane/metadata/android/de/changelogs/730.txt
+++ b/fastlane/metadata/android/de/changelogs/730.txt
@@ -1,2 +1,2 @@
# Behoben
-- erneuter Hotfix des Entschlüsselungsfunktionsfehlers.
+- Fehler bei der Entschlüsselungsfunktion erneut behoben.
diff --git a/fastlane/metadata/android/de/changelogs/740.txt b/fastlane/metadata/android/de/changelogs/740.txt
index 0d28a157a..063e5a3c7 100644
--- a/fastlane/metadata/android/de/changelogs/740.txt
+++ b/fastlane/metadata/android/de/changelogs/740.txt
@@ -1,12 +1,12 @@
Verbesserungen
-- Make Links in Kommentare klickbar, erhöhen Textgröße
-- seek zum Klicken von Zeitstempel-Links in Kommentare
-- Beliebte Registerkarte basierend auf kürzlich ausgewähltem Zustand anzeigen
-- Add-Unterstützung für Invidious links
+- Links in Kommentaren anklickbar machen, Textgröße erhöhen
+- Bei Anklicken von Zeitstempel-Links in Kommentaren suchen
+- Bevorzugte Registerkarte basierend auf zuletzt ausgewähltem Status anzeigen
+- Unterstützung für Invidious-Links
-Fixed
+Behoben
-- fixed scroll w/kommentare und verwandten Streams deaktiviert
-- fixiert CheckForNewAppVersionTask wird ausgeführt, wenn es sollten't
+- Scrollen mit deaktivierten Kommentaren und verwandten Streams behoben
+- CheckForNewAppVersionTask wird nicht mehr ausgeführt, wenn es nicht sollte
diff --git a/fastlane/metadata/android/de/changelogs/750.txt b/fastlane/metadata/android/de/changelogs/750.txt
index 78a25282a..5dd4766df 100644
--- a/fastlane/metadata/android/de/changelogs/750.txt
+++ b/fastlane/metadata/android/de/changelogs/750.txt
@@ -1,15 +1,15 @@
Neu
-Playback Lebenslauf #2288
-• Resume Streams, wo Sie letztes Mal aufgehört haben
-Downloader Verbesserungen #2149
-
+Wiedergabe fortsetzen #2288
+Downloader-Verbesserungen #2149
Verbessert
-• Gemaketten entfernen #2295
-• Handle (auto)Rotationsänderungen während des Aktivitätszyklus #2444
+• GEMA-Strings entfernt #2295
+• (Automatische) Rotationsänderungen #2444
+• Menüs bei langem Drücken #2368
Behoben
-• Fixed Downloads bei 99,9% #2440
-• Aktualisieren der Spielwarteschlange Metadaten #2453
-• [SoundCloud] Fester Absturz beim Laden von Wiedergabelisten TeamNewPipe/NewPipeExtractor#170
-• [YouTube] Feste Dauer kann nicht paresd TeamNewPipe/NewPipeExtractor#177
+• Untertitelnamenanzeige #2394
+• Absturz, wenn die Überprüfung auf App-Updates fehlschlägt (GitHub-Version) #2423
+• Downloads, die bei 99,9 % hängen bleiben #2440
+• Metadaten der Wiedergabeliste aktualisieren #2453
+• [SoundCloud] Absturz beim Laden von Wiedergabelisten TeamNewPipe/NewPipeExtractor#170
diff --git a/fastlane/metadata/android/de/changelogs/952.txt b/fastlane/metadata/android/de/changelogs/952.txt
index 309b02b09..33e1cbc23 100644
--- a/fastlane/metadata/android/de/changelogs/952.txt
+++ b/fastlane/metadata/android/de/changelogs/952.txt
@@ -1,7 +1,7 @@
-Verbesserungen
+Verbessert
• Autoplay ist nun für alle Services verfügbar (nicht nur für YouTube)
-Reparaturen
+Behoben
• Verwandte Streams wurden behoben, indem die neuen Streamfortsetzungen von YouTube unterstützt werden
• Altersbeschränkte Videos repariert
• [Android TV] Überlagerung von Fokus-Hervorhebungen behoben
diff --git a/fastlane/metadata/android/de/changelogs/972.txt b/fastlane/metadata/android/de/changelogs/972.txt
index c05cf182f..0d5be70e8 100644
--- a/fastlane/metadata/android/de/changelogs/972.txt
+++ b/fastlane/metadata/android/de/changelogs/972.txt
@@ -1,11 +1,14 @@
Neu
-Erkennung von Zeitstempeln und Hashtags in der Beschreibung
-Manuelle Einstellung des Tablet-Modus hinzugefügt
-Abgespielte Elemente können nun in einem Feed ausgeblendet werden
+Erkennung von Zeitstempeln/Hashtags in der Beschreibung
+Manuelle Einstellung des Tablet-Modus
+Abgespielte Elemente können nun im Feed ausgeblendet werden
Verbessert
-Korrekte Unterstützung des Storage Access Framework
-Bessere Fehlerbehandlung von nicht verfügbaren und beendeten Kanälen
-Das Android Share Sheet für Android >=10 Nutzer zeigt nun den Titel des Inhalts an.
-Aktualisierte Invidious Instanzen und Unterstützung von Piped Links.
-...
+Korrekte Unterstützung des Storage-Access-Frameworks
+Bessere Fehlerbehandlung von nicht verfügbaren und geschlossenen Kanälen
+Das Android-Freigabefenster für Nutzer von Android 10+ zeigt nun den Titel des Inhalts an
+Invidious-Instanzen aktualisiert und Unterstützung von Piped-Links
+
+Behoben
+[YouTube] Altersbeschränkte Inhalte
+…
diff --git a/fastlane/metadata/android/de/changelogs/986.txt b/fastlane/metadata/android/de/changelogs/986.txt
index 044365eb8..a1bc3217a 100644
--- a/fastlane/metadata/android/de/changelogs/986.txt
+++ b/fastlane/metadata/android/de/changelogs/986.txt
@@ -1,16 +1,15 @@
-Neu:
+Neu
• Benachrichtigungen für neue Streams
• Nahtloser Übergang zwischen Hintergrund- und Videoplayer
-• Änderung der Tonhöhe um Halbtöne
+• Ändern der Tonhöhe um Halbtöne
• Warteschlange des Hauptplayers an Wiedergabeliste anfügen
-Verbessert:
-• Geschwindigkeit/Tonhöhenschrittgröße speichern
+Verbessert
+• Speichern der Geschwindigkeit/Tonhöhenschrittweite
• Anfängliche lange Videoplayer-Pufferung verringert
• Player-UI für Android TV
-• Löschbestätigung für alle heruntergeladenen Dateien
+• Löschbestätigung aller heruntergeladenen Dateien
-Behoben:
-• Medienschaltfläche blendet die Steuerelemente des Players nicht aus
-• Rücksetzung der Wiedergabe bei Änderung des Playertyps
-• Drehung des Wiedergabelisten-Dialogs
+Behoben
+• Medienschaltfläche blendet Player-Steuerelemente nicht aus
+• …
diff --git a/fastlane/metadata/android/de/changelogs/987.txt b/fastlane/metadata/android/de/changelogs/987.txt
index f7bc9bd80..a03048973 100644
--- a/fastlane/metadata/android/de/changelogs/987.txt
+++ b/fastlane/metadata/android/de/changelogs/987.txt
@@ -1,12 +1,12 @@
-Neu:
-• Unterstützung anderer Übertragungsmethoden als progressives HTTP: schnellere Ladezeit der Wiedergabe, Korrekturen für PeerTube und SoundCloud, Wiedergabe von kürzlich beendeten YouTube-Livestreams
-• Schaltfläche um entfernte Wiedergabeliste einer lokalen Wiedergabeliste hinzuzufügen
-• Bildvorschau im Android 10+ Teilen-Dialog
+Neu
+• Unterstützung anderer Übertragungsmethoden als progressives HTTP: schnellere Ladezeit bei Wiedergabe, Fehlerbehebungen für PeerTube/SoundCloud, Wiedergabe kürzlich beendeter YouTube-Livestreams
+• Schaltfläche, um Remote-Wiedergabeliste einer Lokalen hinzuzufügen
+• Bildvorschau im Teilen-Dialog von Android 10+
-Verbessert:
+Verbessert
• Wiedergabewerte-Dialog
-• Import/Export-Schaltflächen für Abonnements in das Drei-Punkte-Menü verschoben
+• Import/Export-Schaltflächen für Abos in Drei-Punkte-Menü verschoben
-Behoben:
-• Entfernung von vollständig angesehenen Videos aus der Wiedergabeliste
-• Freigabemenü-Design und „Zur Wiedergabeliste hinzufügen“-Eintrag
+Behoben
+• Entfernen vollständig angesehener Videos aus Wiedergabeliste
+• …
diff --git a/fastlane/metadata/android/de/changelogs/997.txt b/fastlane/metadata/android/de/changelogs/997.txt
index f55e72b05..fbb5727d8 100644
--- a/fastlane/metadata/android/de/changelogs/997.txt
+++ b/fastlane/metadata/android/de/changelogs/997.txt
@@ -1,17 +1,16 @@
Neu
• Antwort auf Kommentar
• Wiedergabelisten umordnen
-• Wiedergabelisten-Beschreibung und -Dauer
+• Wiedergabelisten-Beschreibung/-Dauer
• Rücksetzen der Einstellungen
Verbessert
-• [Android 13+] Wiederherstellen benutzerdef. Benachrichtigungsaktionen
-• Zustimmung zur Update-Prüfung
-• Während Pufferung Abspielen/Pause über Benachrichtigung
-• Neuordnung einiger Einstellungen
+• [Android 13+] Wiederherstellen benutzerd. Benachrichtigungsaktionen
+• Zustimmung zur Updateprüfung
+• Wiedergabe/Pause von Benachrichtigungen während Pufferung
+• Neuanordnung einiger Einstellungen
Behoben
-• [YouTube] Kommentare wurden nicht geladen, weitere Korrekturen und Verbesserungen
+• [YouTube] Kommentare wurden nicht geladen, weitere Fehlerbehebungen/Verbesserungen
• Sicherheitslücke beim Einstellungsimport und Umstellung auf JSON
-• Verschiedene Download-Korrekturen
-• Suchtext gekürzt
+• …
diff --git a/fastlane/metadata/android/de/changelogs/999.txt b/fastlane/metadata/android/de/changelogs/999.txt
index 51cf80d3e..059b4e081 100644
--- a/fastlane/metadata/android/de/changelogs/999.txt
+++ b/fastlane/metadata/android/de/changelogs/999.txt
@@ -4,9 +4,9 @@ Neu
• [SoundCloud] Unterstützung für on.soundcloud.com-URLs hinzugefügt
Verbessert
-• [Bandcamp]Anzeige zusätzlicher Informationen im Radio-Kiosk
+• [Bandcamp] Anzeige zusätzlicher Informationen im Radio-Kiosk
Behoben
-• [YouTube] Behebung gelegentlicher HTTP 403-Fehler am Anfang oder in der Mitte von Videos
+• [YouTube] Behebung gelegentlicher HTTP-403-Fehler am Anfang oder in der Mitte von Videos
• [YouTube] Extrahieren von Avataren und Banner aus mehr Kanal-Header-Typen
• [Bandcamp] Verschiedene Fehler behoben und HTTPS wird stets verwendet
diff --git a/fastlane/metadata/android/de/short_description.txt b/fastlane/metadata/android/de/short_description.txt
index ec47872eb..6afdb21ea 100644
--- a/fastlane/metadata/android/de/short_description.txt
+++ b/fastlane/metadata/android/de/short_description.txt
@@ -1 +1 @@
-Eine freie, leichte YouTube-App für Android.
+Eine kostenlose, leichte YouTube-App für Android.
diff --git a/fastlane/metadata/android/el/changelogs/1004.txt b/fastlane/metadata/android/el/changelogs/1004.txt
new file mode 100644
index 000000000..d00799cfd
--- /dev/null
+++ b/fastlane/metadata/android/el/changelogs/1004.txt
@@ -0,0 +1,3 @@
+Αυτή η έκδοση διορθώνει το πρόβλημα που παρουσίαζε το YouTube μόνο σε ροή 360p.
+
+Σημειώστε ότι η λύση που χρησιμοποιείται σε αυτήν την έκδοση είναι πιθανώς προσωρινή και μακροπρόθεσμα πρέπει να εφαρμοστεί το πρωτόκολλο βίντεο SABR, αλλά τα μέλη του TeamNewPipe είναι απασχολημένα αυτήν τη στιγμή, επομένως οποιαδήποτε βοήθεια θα εκτιμηθεί ιδιαίτερα! https://github.com/TeamNewPipe/NewPipe/issues/12248
diff --git a/fastlane/metadata/android/el/changelogs/1005.txt b/fastlane/metadata/android/el/changelogs/1005.txt
new file mode 100644
index 000000000..286239c25
--- /dev/null
+++ b/fastlane/metadata/android/el/changelogs/1005.txt
@@ -0,0 +1,17 @@
+Νέο
+• Προσθήκη υποστήριξης για το Android Auto
+• Επιτρέπεται ο ορισμός ομάδων ροών ως καρτέλες κύριας οθόνης
+• [YouTube] Κοινή χρήση ως προσωρινή λίστα αναπαραγωγής
+• [SoundCloud] Καρτέλα καναλιού "Μου αρέσει"
+
+Βελτιωμένη
+• Καλύτερες υποδείξεις γραμμής αναζήτησης
+• Εμφάνιση ημερομηνίας λήψης στις Λήψεις
+• Χρήση γλώσσας Android 13 ανά εφαρμογή
+
+Διορθώθηκε
+• Διόρθωση σπασμένων χρωμάτων κειμένου σε σκοτεινή λειτουργία
+• [YouTube] Διόρθωση λιστών αναπαραγωγής που δεν φόρτωναν περισσότερα από 100 στοιχεία
+• [YouTube] Διόρθωση προτεινόμενων βίντεο που λείπουν
+• Διόρθωση σφαλμάτων στην προβολή λίστας ιστορικού
+• Διόρθωση χρονικών σημάνσεων στις απαντήσεις σχολίων
diff --git a/fastlane/metadata/android/el/changelogs/70.txt b/fastlane/metadata/android/el/changelogs/70.txt
new file mode 100644
index 000000000..7d1be05ff
--- /dev/null
+++ b/fastlane/metadata/android/el/changelogs/70.txt
@@ -0,0 +1,25 @@
+ΠΡΟΣΟΧΗ: Αυτή η έκδοση πιθανότατα έχει πολλά bugs, όπως και η προηγούμενη. Ωστόσο, λόγω του πλήρους τερματισμού λειτουργίας από την έκδοση 17, μια προβληματική έκδοση είναι καλύτερη από καμία έκδοση. Σωστά; ¯\_(ツ)_/¯
+
+### Βελτιώσεις
+* τα ληφθέντα αρχεία μπορούν πλέον να ανοιχτούν με ένα κλικ #1879
+* κατάργηση υποστήριξης για android 4.1 - 4.3 #1884
+* κατάργηση παλιού προγράμματος αναπαραγωγής #1884
+* κατάργηση ροών από την τρέχουσα ουρά αναπαραγωγής σύροντάς τες προς τα δεξιά #1915
+* κατάργηση της αυτόματης ροής σε ουρά όταν μια νέα ροή μπαίνει στην ουρά χειροκίνητα #1878
+* Επεξεργασία μετά την επεξεργασία για λήψεις και εφαρμογή ελλειπουσών λειτουργιών #1759 από @kapodamy
+* Υποδομή μετεπεξεργασίας
+* Σωστός χειρισμός σφαλμάτων "υποδομής" (για πρόγραμμα λήψης)
+* Ουρά αντί για πολλαπλές λήψεις
+* Μετακίνηση σειριοποιημένων εκκρεμών λήψεων (αρχεία `.giga`) στα δεδομένα εφαρμογής
+* Εφαρμογή μέγιστης επανάληψης λήψης
+* Σωστή παύση λήψης πολλαπλών νημάτων
+* Διακοπή λήψεων κατά τη μετάβαση σε δίκτυο κινητής τηλεφωνίας (δεν λειτουργεί ποτέ, δείτε το 2ο σημείο)
+* Αποθήκευση του αριθμού νημάτων για τις επόμενες λήψεις
+* Πολλά Διορθώθηκαν οι ασυνέπειες
+
+### Διορθώθηκε
+* Διορθώθηκε το σφάλμα με την προεπιλεγμένη ανάλυση να έχει οριστεί στην καλύτερη και την περιορισμένη ανάλυση δεδομένων κινητής τηλεφωνίας #1835
+* διορθώθηκε το σφάλμα του αναδυόμενου προγράμματος αναπαραγωγής #1874
+* NPE κατά την προσπάθεια ανοίγματος του προγράμματος αναπαραγωγής φόντου #1901
+* Διορθώθηκε η εισαγωγή νέων ροών όταν είναι ενεργοποιημένη η αυτόματη ουρά #1878
+* Διορθώθηκε το πρόβλημα αποκρυπτογράφησης του shuttown
diff --git a/fastlane/metadata/android/el/changelogs/71.txt b/fastlane/metadata/android/el/changelogs/71.txt
new file mode 100644
index 000000000..30163bcb0
--- /dev/null
+++ b/fastlane/metadata/android/el/changelogs/71.txt
@@ -0,0 +1,10 @@
+### Βελτιώσεις
+* Προσθήκη ειδοποίησης ενημέρωσης εφαρμογής για την έκδοση GitHub (#1608 από @krtkush)
+* Διάφορες βελτιώσεις στο πρόγραμμα λήψης (#1944 από @kapodamy):
+* προσθήκη λευκών εικονιδίων που λείπουν και χρήση σκληροπυρηνικής μεθόδου για αλλαγή των χρωμάτων των εικονιδίων
+* έλεγχος εάν ο επαναλήπτης έχει αρχικοποιηθεί (διορθώσεις #2031)
+* δυνατότητα επανάληψης λήψεων με σφάλμα "αποτυχία μετα-επεξεργασίας" στον νέο πολυπλέκτη
+* νέος πολυπλέκτης MPEG-4 που διορθώνει μη σύγχρονες ροές βίντεο και ήχου (#2039)
+
+### Διορθώθηκε
+* Οι ζωντανές ροές YouTube σταματούν να αναπαράγονται μετά από σύντομο χρονικό διάστημα (#1996 από @yausername)
diff --git a/fastlane/metadata/android/en-US/changelogs/1006.txt b/fastlane/metadata/android/en-US/changelogs/1006.txt
new file mode 100644
index 000000000..15b974b97
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/1006.txt
@@ -0,0 +1,16 @@
+# Improved
+Keep current player when clicking on timestamps
+Try to recover pending download missions when possible
+Add option to delete a download without also deleting file
+Overlay Permission: display explanatory dialog for Android > R
+Support on.soundcloud link opening
+A lot of small improvements and optimizations
+
+# Fixed
+Fix short count formatting for Android versions below 7
+Fix ghost notifications
+Fixes for SRT subtitle files
+Fixed tons of crashes
+
+# Development
+Internal code modernization
\ No newline at end of file
diff --git a/fastlane/metadata/android/en_GB/changelogs/1005.txt b/fastlane/metadata/android/en_GB/changelogs/1005.txt
new file mode 100644
index 000000000..7d76f491a
--- /dev/null
+++ b/fastlane/metadata/android/en_GB/changelogs/1005.txt
@@ -0,0 +1,17 @@
+New
+• Add support for Android Auto
+• Allow setting feed groups as main screen tabs
+• [YouTube] Share as temporary playlist
+• [SoundCloud] Likes channel tab
+
+Improved
+• Better search bar hints
+• Show download date in Downloads
+• Use Android 13 per-app language
+
+Fixed
+• Fix broken text colours in dark mode
+• [YouTube] Fix playlists not loading more than 100 items
+• [YouTube] Fix missing recommended videos
+• Fix crashes in History list view
+• Fix timestamps in comment replies
diff --git a/fastlane/metadata/android/en_GB/changelogs/63.txt b/fastlane/metadata/android/en_GB/changelogs/63.txt
new file mode 100644
index 000000000..9044e96bf
--- /dev/null
+++ b/fastlane/metadata/android/en_GB/changelogs/63.txt
@@ -0,0 +1,8 @@
+### Improvements
+- Import/export settings #1333
+- Reduce overdraw (performance improvement) #1371
+- Small code improvements #1375
+- Add everything about GDPR #1420
+
+### Fixed
+- Downloader: Fix crash on loading unfinished downloads from .giga files #1407
diff --git a/fastlane/metadata/android/en_GB/changelogs/64.txt b/fastlane/metadata/android/en_GB/changelogs/64.txt
new file mode 100644
index 000000000..d2ab61203
--- /dev/null
+++ b/fastlane/metadata/android/en_GB/changelogs/64.txt
@@ -0,0 +1,8 @@
+### Improvements
+- Added the ability to limit video quality if using mobile data. #1339
+- Remember brightness for the session #1442
+- Improve download performance for weaker CPUs #1431
+- add (working) support for media session #1433
+
+### Fix
+- Fix crash on opening downloads (fix now available for release builds) #1441
diff --git a/fastlane/metadata/android/es/changelogs/1005.txt b/fastlane/metadata/android/es/changelogs/1005.txt
new file mode 100644
index 000000000..b60b51760
--- /dev/null
+++ b/fastlane/metadata/android/es/changelogs/1005.txt
@@ -0,0 +1,17 @@
+New
+Añadido soporte a Android Auto
+Pemitir configurar grupos de feeds como pestaña en la pantalla principal
+[YouTube] Compartir como playlist temporal
+[SoundCloud] Pestaña de likes en el canal
+
+Mejoras
+Mejores sugerencias en la barra de busqueda
+Mostrar la fecha de descargas en Descargas
+Usar el idioma por aplicacion en Android 13
+
+Arreglos
+Arreglado texto de colores rotos en el modo oscuro
+[YouTube] Solucionado el problema que las playlist con mas de 100 elementos no cargaban
+[YouTube] Solucionado problema de no mostrar los videos recomendados
+Solucionado cierres inesperados en vista de listas en Historial
+Arreglado marcas de tiempo en respuestas de comentarios
diff --git a/fastlane/metadata/android/fr/changelogs/1000.txt b/fastlane/metadata/android/fr/changelogs/1000.txt
index d4e706e2e..994b6061d 100644
--- a/fastlane/metadata/android/fr/changelogs/1000.txt
+++ b/fastlane/metadata/android/fr/changelogs/1000.txt
@@ -1,13 +1,13 @@
-Amélioré
-• Rendre la description de la playlist cliquable pour afficher plus / moins de contenu
-• [PeerTube] Gérer automatiquement les liens d'instance `subscribeto.me`
-• Ne commencer à lire qu'un seul élément dans l'écran d'historique
+Améliorations
+• La description de la playlist est désormais cliquable pour afficher plus ou moins de contenu.
+• [PeerTube] Gestion automatique des liens d'instance `subscribeto.me`
+• Lecture d'un seul élément à la fois depuis l'historique
-Corrigé
-• Correction de la visibilité du bouton RSS
-• Correction des plantages de l'aperçu de la barre de recherche
-• Correction de la mise en playlist d'un élément sans vignette
-• Correction de la sortie de la boîte de dialogue de téléchargement avant qu'elle n'apparaisse
-• Correction de la fenêtre contextuelle de mise en file d'attente de la liste des éléments associés
-• Correction de l'ordre dans la boîte de dialogue d'ajout à la playlist
-• Ajuster la disposition des éléments de signet de la playlist
+Corrections
+• Amélioration de la visibilité du bouton RSS
+• Correction des plantages liés à l'aperçu de la barre de progression
+• Correction de l'ajout d'un élément sans vignette à la playlist
+• Correction de la fermeture prématurée de la boîte de dialogue de téléchargement
+• Correction de la fenêtre contextuelle d'ajout à la file d'attente de la liste des éléments associés
+• Amélioration de l'ordre d'affichage dans la boîte de dialogue « Ajouter à la playlist »
+• Ajustement de la mise en page des signets de playlist
diff --git a/fastlane/metadata/android/fr/changelogs/1003.txt b/fastlane/metadata/android/fr/changelogs/1003.txt
index 161ee7fbb..917714bae 100644
--- a/fastlane/metadata/android/fr/changelogs/1003.txt
+++ b/fastlane/metadata/android/fr/changelogs/1003.txt
@@ -1,6 +1,6 @@
-Ceci est une version de correction qui résout les erreurs de YouTube :
-• [YouTube] Correction du non-chargement des informations des vidéos, correction des erreurs HTTP 403 lors de la lecture des vidéos et restauration de la lecture de certaines vidéos à âge restreint
-• Correction des tailles de sous-titres qui ne changent pas
-• Correction du téléchargement des informations deux fois lors de l'ouverture d'un stream
-• [Soundcloud] Suppression des streams protégés par DRM non lisibles
-• Traductions mises à jour
+Cette m.à.j corrective résout les problèmes suivants sur YouTube :
+• [YouTube] Correction du problème de chargement des informations vidéo, des erreurs HTTP 403 lors de la lecture et restauration de la lecture de certaines vidéos à contenu restreint.
+• Correction du problème d'affichage de la taille des sous-titres.
+• Correction du double téléchargement des informations lors de l'ouverture d'un flux.
+• [SoundCloud] Suppression des flux protégés par DRM et illisibles.
+• Traductions mises à jour.
diff --git a/fastlane/metadata/android/fr/changelogs/1005.txt b/fastlane/metadata/android/fr/changelogs/1005.txt
index b7e5ff49f..269ba2105 100644
--- a/fastlane/metadata/android/fr/changelogs/1005.txt
+++ b/fastlane/metadata/android/fr/changelogs/1005.txt
@@ -1,17 +1,17 @@
-Nouveau
-• Prise en charge d'Android Auto
+Nouveautés
+• Ajout de la compatibilité avec Android Auto
• Possibilité de définir des groupes de flux comme onglets de l'écran principal
• [YouTube] Partager comme playlist temporaire
-• [SoundCloud] Onglet « J'aime »
+• [SoundCloud] Onglet « J'aime » sur les chaînes
-Amélioration
-• Amélioration des astuces de la barre de recherche
+Améliorations
+• Amélioration des suggestions de la barre de recherche
• Affichage de la date de téléchargement dans Téléchargements
• Utilisation de la langue par application d'Android 13
-Corrigé
+Corrections
• Correction des couleurs de texte défectueuses en mode sombre
-• [YouTube] Correction des playlists ne chargeant pas plus de 100 éléments
-• [YouTube] Correction des vidéos recommandées manquantes
-• Correction des plantages dans la vue Historique
+• [YouTube] Correction du chargement des playlists de plus de 100 éléments
+• [YouTube] Correction de l'affichage des vidéos recommandées manquantes
+• Correction des plantages dans l'historique
• Correction des horodatages dans les réponses aux commentaires
diff --git a/fastlane/metadata/android/fr/changelogs/1006.txt b/fastlane/metadata/android/fr/changelogs/1006.txt
new file mode 100644
index 000000000..65fbccfd5
--- /dev/null
+++ b/fastlane/metadata/android/fr/changelogs/1006.txt
@@ -0,0 +1,8 @@
+Conservation du lecteur en cours lors du clic sur les horodatages
+Tentative de récupération des téléchargements en attente
+Ajout d'une option pour supprimer un téléchargement sans supprimer le fichier
+Autorisation de superposition : affichage d'une boîte de dialogue explicative pour Android > R
+
+Correction du formatage du nombre court pour les versions Android inférieures à 7
+Correction des notifications fantômes
+Corrections pour les fichiers de sous-titres SRT
diff --git a/fastlane/metadata/android/fr/changelogs/65.txt b/fastlane/metadata/android/fr/changelogs/65.txt
index bb664a3cb..9d06cac17 100644
--- a/fastlane/metadata/android/fr/changelogs/65.txt
+++ b/fastlane/metadata/android/fr/changelogs/65.txt
@@ -1,26 +1,41 @@
### Améliorations
-- L'animation de l'icône du burgermenu a été désactivé #1486
-- Annulation de la suppression des téléchargements #1472
+- Désactivation de l'animation de l'icône du menu hamburger #1486
+
+- Annulation de la suppression des téléchargements #1472
+
- Option de téléchargement dans le menu de partage #1498
-- Ajout d'une option de partage dans le menu "long tap" #1454
-- Réduction du lecteur principal à la sortie #1354
-- Mise à jour de la version de la bibliothèque et correction de la sauvegarde de la base de données #1510
-- Mise à jour de ExoPlayer 2.8.2 #1392
- - La boîte de dialogue de contrôle de la vitesse de lecture a été retravaillée pour prendre en charge différentes tailles de pas pour un changement de vitesse plus rapide.
- - Ajout d'une option d'avance rapide pendant les silences dans le contrôle de la vitesse de lecture. Cela devrait être utile pour les livres audio et certains genres musicaux, et peut apporter une véritable expérience transparente (et peut casser une chanson avec beaucoup de silences =\\).
- - Refonte de la résolution des sources de médias pour permettre le passage des métadonnées avec les médias en interne dans le lecteur, plutôt que de le faire manuellement. Maintenant, nous avons une seule source de métadonnées et elles sont directement disponibles lorsque la lecture commence.
- - Correction des métadonnées des listes de lecture distantes qui ne sont pas mises à jour lorsque de nouvelles métadonnées sont disponibles lors de l'ouverture du fragment de liste de lecture.
- - Diverses corrections de l'interface utilisateur : #1383, les contrôles de notification du lecteur en arrière-plan sont maintenant toujours blancs, il est plus facile de fermer le lecteur popup en le lançant.
+
+- Ajout de l'option de partage au menu contextuel (appui long) #1454
+
+- Réduction du lecteur principal à la fermeture #1354
+
+- Mise à jour de la version de la bibliothèque et correction de la sauvegarde de la base de données #1510
+
+- Mise à jour ExoPlayer 2.8.2 #1392
+
+- Refonte de la boîte de dialogue de contrôle de la vitesse de lecture pour permettre des incréments différents et ainsi accélérer les changements de vitesse.
+
+- Ajout d'une option pour avancer rapidement pendant les silences dans le contrôle de la vitesse de lecture. Cette fonction devrait être utile pour les livres audio et certains genres musicaux, et peut offrir une expérience d'écoute parfaitement fluide (mais peut aussi perturber la lecture d'un morceau comportant de nombreux silences =\\).
+
+- Refonte de la résolution de la source multimédia pour permettre la transmission des métadonnées directement dans le lecteur, au lieu d'une saisie manuelle. Nous disposons désormais d'une source unique de métadonnées, directement disponible au démarrage de la lecture. - Correction du problème de mise à jour des métadonnées des listes de lecture distantes lors de la disponibilité de nouvelles métadonnées à l'ouverture d'un fragment de liste de lecture.
+
+- Diverses corrections d'interface utilisateur : #1383, les commandes de notification du lecteur en arrière-plan sont désormais toujours blanches, fermeture plus facile du lecteur contextuel par un mouvement brusque.
+
- Utilisation d'un nouvel extracteur avec une architecture remaniée pour le multiservice.
### Corrections
-- Correction #1440 Disposition des informations vidéo cassée #1491
-- Correction de l'historique des vues #1497
- - #1495, en mettant à jour les métadonnées (vignette, titre et nombre de vidéos) dès que l'utilisateur accède à la liste de lecture.
- - #1475, en enregistrant une vue dans la base de données lorsque l'utilisateur lance une vidéo sur un lecteur externe sur le fragment de détail.
-- Correction du timeout de la fenêtre en cas de mode popup. #1463 (Corrigé #640)
-- Correction du lecteur vidéo principal #1509
- - Correction du mode répétition entraînant un NPE du lecteur lorsqu'une nouvelle intention est reçue alors que l'activité du lecteur est en arrière-plan.
- - Correction de la réduction du lecteur en popup ne détruisant pas le lecteur lorsque la permission de popup n'est pas accordée.
+- Correction du problème #1440 : affichage incorrect des informations vidéo. #1491
+
+- Correction de l'historique de visionnage. #1497
+
+- #1495 : mise à jour des métadonnées (miniature, titre et nombre de vidéos) dès que l'utilisateur accède à la liste de lecture.
+
+- #1475 : enregistrement d'une vue dans la base de données lorsque l'utilisateur lance une vidéo sur un lecteur externe dans le fragment de détails.
+
+- Correction du délai d'expiration de l'écran en mode contextuel. #1463 (Correction du problème #640)
+
+- Correction du lecteur vidéo principal. #1509
+
+- [#1412] Correction du mode répétition provoquant une exception NullPointerException (NPE) du lecteur lors de la réception d'une nouvelle intention alors que l'activité du lecteur est en arrière-plan. - Correction d'un problème où la réduction du lecteur dans une fenêtre contextuelle ne détruisait pas le lecteur lorsque l'autorisation d'afficher la fenêtre contextuelle n'était pas accordée.
diff --git a/fastlane/metadata/android/fr/changelogs/66.txt b/fastlane/metadata/android/fr/changelogs/66.txt
index 3a94c81e0..b6092f44f 100644
--- a/fastlane/metadata/android/fr/changelogs/66.txt
+++ b/fastlane/metadata/android/fr/changelogs/66.txt
@@ -1,28 +1,50 @@
+# Journal des modifications de la v0.13.7
+
+### Corrigé
+- Correction des problèmes de filtre de tri de la v0.13.6
+
# Journal des modifications de la v0.13.6
### Améliorations
-- L'animation de l'icône du menu « hamburger » a été désactivée #1486
-- Annulation de la suppression des téléchargements #1472
+- Désactivation de l'animation de l'icône du menu hamburger #1486
+
+- Annulation de la suppression des téléchargements #1472
+
- Option de téléchargement dans le menu de partage #1498
-- Ajout d'une option de partage dans le menu "long tap" #1454
-- Réduction du lecteur principal à la sortie #1354
-- Mise à jour de la version de la bibliothèque et correction de la sauvegarde de la base de données #1510
-- Mise à jour de ExoPlayer 2.8.2 #1392
- - La boîte de dialogue de contrôle de la vitesse de lecture a été retravaillée pour prendre en charge différentes tailles de pas pour un changement de vitesse plus rapide.
- - Ajout d'une option d'avance rapide pendant les silences dans le contrôle de la vitesse de lecture. Cela devrait être utile pour les livres audio et certains genres musicaux, et peut apporter une véritable expérience transparente (et peut casser une chanson avec beaucoup de silences =\\).
- - Refonte de la résolution des sources de médias pour permettre le passage des métadonnées avec les médias en interne dans le lecteur, plutôt que de le faire manuellement. Maintenant, nous avons une seule source de métadonnées et elles sont directement disponibles lorsque la lecture commence.
- - Correction des métadonnées des listes de lecture distantes qui ne sont pas mises à jour lorsque de nouvelles métadonnées sont disponibles lors de l'ouverture du fragment de liste de lecture.
- - Diverses corrections de l'interface utilisateur : #1383, les contrôles de notification du lecteur en arrière-plan sont maintenant toujours blancs, il est plus facile de fermer le lecteur popup en le lançant.
+
+- Ajout de l'option de partage au menu contextuel (appui long) #1454
+
+- Réduction du lecteur principal à la fermeture #1354
+
+- Mise à jour de la version de la bibliothèque et correction de la sauvegarde de la base de données #1510
+
+- Mise à jour ExoPlayer 2.8.2 #1392
+
+- Refonte de la boîte de dialogue de contrôle de la vitesse de lecture pour permettre des incréments différents et ainsi accélérer les changements de vitesse.
+
+- Ajout d'une option pour avancer rapidement pendant les silences dans le contrôle de la vitesse de lecture. Ceci devrait être utile pour les livres audio et certains genres musicaux, et peut offrir une expérience d'écoute parfaitement fluide (mais peut aussi perturber une chanson avec de nombreux silences =\\). - Résolution de la source multimédia remaniée pour permettre la transmission interne des métadonnées au lecteur, au lieu d'une saisie manuelle. Les métadonnées proviennent désormais d'une source unique et sont directement disponibles au démarrage de la lecture.
+
+- Correction du problème de mise à jour des métadonnées des listes de lecture distantes lors de l'ouverture d'un fragment de liste de lecture, même lorsque de nouvelles métadonnées sont disponibles.
+
+- Diverses corrections d'interface : #1383, les commandes de notification du lecteur en arrière-plan sont désormais toujours blanches ; il est plus facile de fermer le lecteur contextuel en le faisant glisser.
+
- Utilisation d'un nouvel extracteur avec une architecture remaniée pour le multiservice.
### Corrections
-- Correction #1440 Disposition des informations vidéo cassée #1491
-- Correction de l'historique des vues #1497
- - #1495, en mettant à jour les métadonnées (vignette, titre et nombre de vidéos) dès que l'utilisateur accède à la liste de lecture.
- - #1475, en enregistrant une vue dans la base de données lorsque l'utilisateur lance une vidéo sur un lecteur externe sur le fragment de détail.
-- Correction du timeout de la fenêtre en cas de mode popup. #1463 (Corrigé #640)
-- Correction du lecteur vidéo principal #1509
- - Correction du mode répétition entraînant un NPE du lecteur lorsqu'une nouvelle intention est reçue alors que l'activité du lecteur est en arrière-plan.
- - Correction de la réduction du lecteur en popup ne détruisant pas le lecteur lorsque la permission de popup n'est pas accordée.
+- Correction du problème #1440 : affichage incorrect des informations vidéo ; #1491
+
+- Correction de l'historique de visionnage ; #1497
+
+- #1495 : mise à jour des métadonnées (miniature, titre et nombre de vidéos) dès que l'utilisateur accède à la liste de lecture.
+
+- #1475 : enregistrement d'une vue dans la base de données lorsque l'utilisateur lance une vidéo sur un lecteur externe dans le fragment de détails.
+
+- Correction du délai d'expiration de l'écran en mode fenêtre contextuelle. #1463 (Correction de #640)
+
+- Correction du lecteur vidéo principal #1509
+
+- [#1412] Correction du mode de répétition provoquant une exception de pointeur nul (NPE) du lecteur lors de la réception d'une nouvelle intention alors que l'activité du lecteur est en arrière-plan.
+
+- Correction du problème suivant : la réduction du lecteur dans une fenêtre contextuelle ne le détruisait pas lorsque l'autorisation d'ouvrir une fenêtre contextuelle n'était pas accordée.
diff --git a/fastlane/metadata/android/fr/changelogs/68.txt b/fastlane/metadata/android/fr/changelogs/68.txt
index 9b2760c35..3c9c4446f 100644
--- a/fastlane/metadata/android/fr/changelogs/68.txt
+++ b/fastlane/metadata/android/fr/changelogs/68.txt
@@ -1,31 +1,44 @@
-# Modifications v0.14.1
+# Modifications de la v0.14.1
-### Corrections
-- Échec du décryptage de l'URL vidéo #1659
-- Lien de description, ne s'extrayait pas bien #1657
+### Corrigé
+- Correction du problème de décryptage de l'URL vidéo (#1659)
+- Correction du problème d'extraction du lien de description (#1657)
-# Modifications v0.14.0
+# Modifications de la v0.14.0
-### Nouveautés
-- Design du dossier #1461
-- Page d'accueil personnalisable #1461
+### Nouveau
+- Nouveau design du tiroir (#1461)
+- Nouvelle page d'accueil personnalisable (#1461)
### Améliorations
-- Contrôles gestuels retravaillés #1604
-- Nouvelle façon de fermer le lecteur popup #1597
+- Refonte des commandes gestuelles (#1604)
+- Nouvelle méthode pour fermer le lecteur pop-up (#1597)
-### Corrections
-- Erreur lorsque le nombre d'abonnements n'est pas disponible. Ferme #1649.
- - Affiche "le nombre d'abonnés non disponible" dans ces cas.
-- NPE lorsqu'une liste de lecture YouTube est vide.
-- Kiosques dans SoundCloud
-- Refactor et correction du bug #1623
-- Résultat de recherche cyclique #1562
-- Barre de recherche qui n'est pas mise en page de manière statique
-- Vidéos YT Premium qui ne sont pas bloquées correctement
-- Vidéos qui ne se chargent pas toujours (à cause du parsing DASH)
-- Liens dans la description des vidéos
-- Afficher un avertissement lorsque quelqu'un essaie de télécharger vers une carte SD externe
-- Exception "rien indiqué" qui déclenche un rapport
-- La vignette ne s'affiche pas dans le lecteur de fond pour Android 8.1 [voir ici](https://github.com/TeamNewPipe/NewPipe/issues/943)
-- Enregistrement du récepteur de diffusion. Ferme le dossier #1641.
+### Corrigé
+- Correction d'une erreur lorsque le nombre d'abonnements n'est pas disponible. Résout le problème n° 1649.
+
+ - Afficher « Nombre d'abonnés indisponible » dans ces cas
+
+- Correction d'une exception NPE lorsqu'une playlist YouTube est vide
+
+- Correction rapide pour les bornes interactives sur SoundCloud
+
+- Refactorisation et correction du bug n° 1623
+
+- Correction du résultat de recherche cyclique n° 1562
+
+- Correction de la barre de progression (position statique)
+
+- Correction du blocage incorrect des vidéos YouTube Premium
+
+- Correction du chargement intempestif des vidéos (dû à l'analyse DASH)
+
+- Correction des liens dans la description des vidéos
+
+- Afficher un avertissement lors d'une tentative de téléchargement sur carte SD externe
+
+- Correction d'une exception déclenchant un rapport en cas d'absence d'affichage
+
+- Correction de l'affichage des miniatures dans le lecteur en arrière-plan sous Android 8.1 [voir ici](https://github.com/TeamNewPipe/NewPipe/issues/943)
+
+- Correction de l'enregistrement du récepteur de diffusion. Résout le problème n° 1641.
diff --git a/fastlane/metadata/android/fr/changelogs/70.txt b/fastlane/metadata/android/fr/changelogs/70.txt
index fccfccd2b..185f98f69 100644
--- a/fastlane/metadata/android/fr/changelogs/70.txt
+++ b/fastlane/metadata/android/fr/changelogs/70.txt
@@ -1,4 +1,4 @@
-ATTENTION : Cette version est probablement un festival de bugs, tout comme la dernière. Cependant, en raison de la fermeture complète depuis la 17. une version cassée est mieux que pas de version. N'est-ce pas ? ¯\_(ツ)_/¯
+ATTENTION : Cette version est probablement un festival de bugs, tout comme la dernière. Cependant, en raison de la fermeture complète depuis la 17. une version cassée est mieux que pas de version. N'est-ce pas ? ¯\_(ツ)_/¯
### Améliorations
* Les fichiers téléchargés peuvent maintenant être ouverts en un seul clic.
diff --git a/fastlane/metadata/android/fr/changelogs/740.txt b/fastlane/metadata/android/fr/changelogs/740.txt
index da4bdc2f8..167608b66 100644
--- a/fastlane/metadata/android/fr/changelogs/740.txt
+++ b/fastlane/metadata/android/fr/changelogs/740.txt
@@ -3,7 +3,7 @@
Rendre les liens dans les commentaires cliquables, augmenter la taille du texte
Rechercher en cliquant sur les liens d'horodatage dans les commentaires
Afficher l'onglet préféré en fonction de l'état récemment sélectionné
-Ajouter la liste de lecture à la file d'attente lors d'un clic long sur 'Arrière-plan' dans la fenêtre de la liste de lecture
+Ajouter la playlist à la file d'attente lors d'un clic long sur 'Arrière-plan' dans la fenêtre de la playlist
Rechercher le texte partagé lorsqu'il ne s'agit pas d'une URL
Ajouter "partager à l'heure actuelle" bouton au lecteur vidéo principal lecteur vidéo principal
Ajouter un bouton de fermeture du lecteur principal lorsque la file d'attente vidéo est terminée
@@ -18,6 +18,6 @@
- Défilement avec les commentaires et les flux associés désactivés
- CheckForNewAppVersionTask qui est exécuté alors qu'il ne devrait pas l'être'
-- Importation des abonnements YouTube : ignorer ceux dont l’URL est invalide et conserver ceux dont le titre est vide
-- URL YouTube invalide : le nom de la balise signature n'est pas toujours "signature", ce qui empêche le chargement des flux.
+- Importation des abonnements YouTube : ignorer ceux dont l’URL est invalide et conserver ceux dont le titre est vide
+- URL YouTube invalide : le nom de la balise signature n'est pas toujours "signature", ce qui empêche le chargement des flux.
diff --git a/fastlane/metadata/android/fr/changelogs/750.txt b/fastlane/metadata/android/fr/changelogs/750.txt
index 422529abf..7273ae1f0 100644
--- a/fastlane/metadata/android/fr/changelogs/750.txt
+++ b/fastlane/metadata/android/fr/changelogs/750.txt
@@ -1,22 +1,36 @@
-Nouveau
-Reprise de lecture #2288
-• Reprise des flux où ils s'étaient arrêtés
-Améliorations du téléchargeur #2149
-• Utilisation du Storage Access Framework pour stocker sur cartes SD
-• Nouveau multiplexeur mp4
-• Peut changer le dossier de téléchargement
-• Respect des réseaux tarifés
+Nouveautés
+Reprise de la lecture #2288
+
+• Reprise des flux là où vous les avez interrompus
+Améliorations du téléchargeur #2149
+
+• Utilisation de Storage Access Framework pour stocker les téléchargements sur des cartes SD externes
+
+• Nouveau multiplexeur mp4
+
+• Possibilité de modifier le répertoire de téléchargement avant de lancer un téléchargement
+
+• Respect des réseaux limités
Améliorations
+
• Suppression des chaînes gema #2295
-• Gestion des changements de rotation #2444
-• Uniformisation des menus longue-pression #2368
+
+• Gestion des changements de rotation (automatique) pendant le cycle de vie de l'activité #2444
+
+• Harmonisation des menus accessibles par appui long #2368
Corrections
-• Nom de la piste de sous-titres sélectionnée qui ne s'affiche pas #2394
-• Ne plante pas quand la vérification de la mise à jour de l'application échoue #2423
-• Téléchargements bloqués à 99,9 % #2440
-• Mise à jour des métadonnées de la file de lecture #2453
-• [SoundCloud] Ne plante pas lors du chargement des playlists TeamNewPipe/NewPipeExtractor#170
-• [YouTube] Durée pas analysée TeamNewPipe/NewPipeExtractor#177
+
+• Correction de l'affichage du nom de la piste de sous-titres sélectionnée #2394
+
+• Correction du plantage en cas d'échec de la vérification des mises à jour de l'application (version GitHub) #2423
+
+• Correction du blocage des téléchargements à 99,9 % #2440
+
+• Mise à jour des métadonnées de la file d'attente de lecture #2453
+
+• [SoundCloud] Correction du plantage lors du chargement des playlists TeamNewPipe/NewPipeExtractor#170
+
+• [YouTube] Correction de l'impossibilité d'afficher la durée paresd TeamNewPipe/NewPipeExtractor#177
diff --git a/fastlane/metadata/android/fr/changelogs/760.txt b/fastlane/metadata/android/fr/changelogs/760.txt
index 2f74c57b4..e0a225fce 100644
--- a/fastlane/metadata/android/fr/changelogs/760.txt
+++ b/fastlane/metadata/android/fr/changelogs/760.txt
@@ -5,7 +5,7 @@ Nouveauté
Améliorations
-• Ajout de l'action "Commencer à jouer ici" dans les menus qui s'appuient longuement pour les listes de lecture #2518
+• Ajout de l'action "Commencer à jouer ici" dans les menus qui s'appuient longuement pour les playlists #2518
• Ajout d'un commutateur pour le sélecteur de fichiers SAF / hérité #2521
Corrections
@@ -13,7 +13,7 @@ Corrections
• Correction de la position de lecture qui est enregistrée même si l'historique de visionnage est désactivé
• Correction des performances réduites causées par la position de lecture dans les vues de liste #2517
• [Extractor] Correction de ReCaptchaActivity #2527, TeamNewPipe/NewPipeExtractor#186
-• [Extractor] [YouTube] Correction de l'erreur de recherche occasionnelle lorsque les listes de lecture sont dans les résultats TeamNewPipe/NewPipeExtractor#185
+• [Extractor] [YouTube] Correction de l'erreur de recherche occasionnelle lorsque les playlists sont dans les résultats TeamNewPipe/NewPipeExtractor#185
@@ -39,5 +39,5 @@ Corrections
• Ne plante pas lorsque la vérification de la mise à jour de l'application échoue (version GitHub) #2423
• Correction des téléchargements bloqués à 99,9 % #2440
• Mise à jour des métadonnées de la file de lecture #2453
-• [SoundCloud] Correction du plantage lors du chargement des listes de lecture TeamNewPipe/NewPipeExtractor#170
+• [SoundCloud] Correction du plantage lors du chargement des playlists TeamNewPipe/NewPipeExtractor#170
• [YouTube] Correction de la durée qui ne peut pas être analysée TeamNewPipe/NewPipeExtractor#177
diff --git a/fastlane/metadata/android/fr/changelogs/800.txt b/fastlane/metadata/android/fr/changelogs/800.txt
index 91bd24d54..46fe1504e 100644
--- a/fastlane/metadata/android/fr/changelogs/800.txt
+++ b/fastlane/metadata/android/fr/changelogs/800.txt
@@ -1,10 +1,10 @@
Nouveau
-- Support de PeerTube sans P2P (#2201) [Beta] :
+- Support de PeerTube sans P2P (#2201) [Beta] :
◦ Regarder et télécharger des vidéos depuis des instances PeerTube
◦ Ajouter des instances dans les paramètres pour accéder à l'ensemble du monde PeerTube
◦ Il peut y avoir des problèmes avec les handshakes SSL sur Android 4.4 et 7.1 lors de l'accès à certaines instances, ce qui entraîne une erreur de réseau.
-- Téléchargeur (#2679) :
+- Téléchargeur (#2679) :
◦ Calculer l'heure d'arrivée du téléchargement
◦ Télécharger les opus (fichiers webm) en ogg
◦ Récupération des liens de téléchargement expirés pour reprendre les téléchargements après une longue pause
@@ -17,7 +17,7 @@ Amélioré
Correction
- Correction d'un bogue qui ne permettait pas de déplacer le lecteur popup si un autre doigt était placé pendant le déplacement du lecteur popup #2772
-- Autorise les listes de lecture sans uploader et corrige les crashs liés à ce problème #2724, TeamNewPipe/NewPipeExtractor#219
+- Autorise les playlists sans uploader et corrige les crashs liés à ce problème #2724, TeamNewPipe/NewPipeExtractor#219
- Activation de TLS1.1/1.2 sur les appareils Android 4.4 (API 19/KitKat) pour corriger le handshake TLS avec MediaCCC et certaines instances PeerTube #2792
- SoundCloud] Correction de l'extraction de l'identifiant client TeamNewPipe/NewPipeExtractor#217
- [SoundCloud] Correction de l'extraction du flux audio
diff --git a/fastlane/metadata/android/fr/changelogs/810.txt b/fastlane/metadata/android/fr/changelogs/810.txt
index c40bea4af..573ea9889 100644
--- a/fastlane/metadata/android/fr/changelogs/810.txt
+++ b/fastlane/metadata/android/fr/changelogs/810.txt
@@ -2,10 +2,10 @@ Nouveautée :
• Affiche la miniature de la vidéo sur l'écran de verrouillage lorsqu'elle est lu en arrière-plan
Améliorations :
-• Ajout de la liste de lecture locale à la file d'attente lors d'une pression longue sur le bouton arrière-plan / flottant
+• Ajout de la playlist locale à la file d'attente lors d'une pression longue sur le bouton arrière-plan / flottant
• Possibilité de faire défiler les onglets de la page principale et les masquent lorsqu'il n'y a qu'un seul onglet
• Limite le nombre de mises à jour de la miniature des notifications avec le lecteur en arrière-plan
-• Ajout d'une miniature fictive pour les listes de lecture locales vides
+• Ajout d'une miniature fictive pour les playlists locales vides
• Utilisation de l'extension de fichier *.opus au lieu de *.webm et affiche « opus » pour le nom du format au lieu de « WebM Opus » dans la liste déroulante de téléchargement.
• Ajout d'un bouton pour supprimer les fichiers téléchargés ou l'historique de téléchargements dans les « Téléchargements »
• [YouTube] Ajout de la prise en charge des liens de chaînes /c/shortened_url
diff --git a/fastlane/metadata/android/fr/changelogs/840.txt b/fastlane/metadata/android/fr/changelogs/840.txt
index fa7cf4986..240b77824 100644
--- a/fastlane/metadata/android/fr/changelogs/840.txt
+++ b/fastlane/metadata/android/fr/changelogs/840.txt
@@ -7,7 +7,7 @@ Amélioré
• Corriger l'activité ReCaptcha et enregistrer correctement les cookies obtenus
• Suppression du menu à points au profit du tiroir et du bouton Masquer l'historique lorsque l'historique de visionnage n'est pas activé dans les paramètres
• Demander correctement l'autorisation d'affichage sur d'autres applications dans les paramètres sur Android 6 et versions ultérieures
-• Renommer la liste de lecture locale en cliquant longuement dans BookmarkFragment
+• Renommer la playlist locale en cliquant longuement dans BookmarkFragment
• Diverses améliorations de PeerTube
• Amélioration de plusieurs chaînes sources en anglais
diff --git a/fastlane/metadata/android/fr/changelogs/958.txt b/fastlane/metadata/android/fr/changelogs/958.txt
index 9f857d470..27908767f 100644
--- a/fastlane/metadata/android/fr/changelogs/958.txt
+++ b/fastlane/metadata/android/fr/changelogs/958.txt
@@ -1,13 +1,13 @@
-Nouveautés :
+Nouveautés :
• Tirer pour actualiser les abonnements
• Option pour masquer la miniature sur l'écran de verrouillage de nouveau dispo.
• Amélioration du chargement des listes locales (playlists, historique…)
-Corrigé :
+Corrigé :
• Crash au démarrage quand NewPipe n'était plus dans la RAM
• Crash au démarrage quand l'appareil n'était pas connecté à internet
• Paramètres de luminosité et de volume
-• [YouTube] Listes de lecture longues
+• [YouTube] Playlists longues
-Autres :
+Autres :
• Mise à jour des traductions
diff --git a/fastlane/metadata/android/fr/changelogs/968.txt b/fastlane/metadata/android/fr/changelogs/968.txt
index 06b84c7fd..abf53af53 100644
--- a/fastlane/metadata/android/fr/changelogs/968.txt
+++ b/fastlane/metadata/android/fr/changelogs/968.txt
@@ -1,5 +1,5 @@
Ajout d'une option de détails sur les chaînes dans le menu de pression longue.
-Ajout d'une fonctionnalité permettant de renommer le nom de la liste de lecture à partir de l'interface de la liste de lecture.
+Ajout d'une fonctionnalité permettant de renommer le nom de la playlist à partir de l'interface de la playlist.
Permet à l'utilisateur de faire une pause pendant la mise en mémoire tampon d'une vidéo.
Le thème blanc a été amélioré.
Correction du chevauchement des polices lors de l'utilisation d'une taille de police plus grande.
diff --git a/fastlane/metadata/android/fr/changelogs/980.txt b/fastlane/metadata/android/fr/changelogs/980.txt
index 6835f70c8..149ff2eeb 100644
--- a/fastlane/metadata/android/fr/changelogs/980.txt
+++ b/fastlane/metadata/android/fr/changelogs/980.txt
@@ -1,5 +1,5 @@
Nouveautés
-• Ajout option "Ajouter à la liste de lecture" au menu de partage
+• Ajout option "Ajouter à la playlist" au menu de partage
• Ajout prise en charge des liens courts y2u.be et PeerTube
Améliorations
diff --git a/fastlane/metadata/android/fr/changelogs/983.txt b/fastlane/metadata/android/fr/changelogs/983.txt
index b9760a8a1..5079132f0 100644
--- a/fastlane/metadata/android/fr/changelogs/983.txt
+++ b/fastlane/metadata/android/fr/changelogs/983.txt
@@ -6,4 +6,4 @@ Ajoute les notifications d’erreur
Corrige la relecture du premier item de la file lorsque le lecteur change
Attend plus longtemps lors des directs avant d’échouer
Corrige l’ordre des résultats d’une recherche locale
-Corrige les champs d’item vides dans la liste de lecture
+Corrige les champs d’item vides dans la playlist
diff --git a/fastlane/metadata/android/fr/changelogs/986.txt b/fastlane/metadata/android/fr/changelogs/986.txt
index b5f2af821..af6901a0a 100644
--- a/fastlane/metadata/android/fr/changelogs/986.txt
+++ b/fastlane/metadata/android/fr/changelogs/986.txt
@@ -2,7 +2,7 @@ Ajouts
• Notifications pour les nouveaux flux
• Transition fluide entre les lecteurs vidéo et en arrière-plan
• Modification de la hauteur de son par demi-tons
-• Ajout de la file du lecteur principal dans une liste de lecture
+• Ajout de la file du lecteur principal dans une playlist
Améliorations
• Enregistrement du pas de la vitesse et de la hauteur audios
diff --git a/fastlane/metadata/android/fr/changelogs/987.txt b/fastlane/metadata/android/fr/changelogs/987.txt
index 1641d9a00..00000725d 100644
--- a/fastlane/metadata/android/fr/changelogs/987.txt
+++ b/fastlane/metadata/android/fr/changelogs/987.txt
@@ -1,6 +1,6 @@
Nouveautés
-• Prise en charge d'autres méthodes de diffusion que le HTTP progressif : temps de chargement plus rapide, corrections pour PeerTube et SoundCloud, lecture des nouveaux flux en directs de YouTube
-• Bouton pour ajouter une liste de lecture distante à une locale
+• Prise en charge d'autres méthodes de diffusion que le HTTP progressif : temps de chargement plus rapide, corrections pour PeerTube et SoundCloud, lecture des nouveaux flux en directs de YouTube
+• Bouton pour ajouter une playlist distante à une locale
• Prévisualisation d'images lors d'un partage pour Andoid 10+
Améliorations
diff --git a/fastlane/metadata/android/fr/changelogs/990.txt b/fastlane/metadata/android/fr/changelogs/990.txt
index fcab79c3c..b941066e2 100644
--- a/fastlane/metadata/android/fr/changelogs/990.txt
+++ b/fastlane/metadata/android/fr/changelogs/990.txt
@@ -1,9 +1,9 @@
-Cette mise à jour abandonne la prise en charge d'Android 4.4 KitKat, la nouvelle version minimum est Android 5 Lollipop !
+Cette mise à jour abandonne la prise en charge d'Android 4.4 KitKat, la nouvelle version minimum est Android 5 Lollipop !
Nouveautés
• Télécharger depuis le menu d'appuis long
• Cacher les futures vidéos dans le flux
-• Partager des listes de lecture locales
+• Partager des playlists locales
Améliorations
• Réusinage du code du lecteur en petits composants : moins de mémoire vive utilisée, moins de bogues
diff --git a/fastlane/metadata/android/fr/changelogs/992.txt b/fastlane/metadata/android/fr/changelogs/992.txt
index 88e58db96..dc1fad35b 100644
--- a/fastlane/metadata/android/fr/changelogs/992.txt
+++ b/fastlane/metadata/android/fr/changelogs/992.txt
@@ -1,7 +1,7 @@
Nouveau
• Nombre d'abonnés dans les détails de la vidéo
• Télécharger depuis la file d'attente
-• Définir de manière permanente une miniature de liste de lecture
+• Définir de manière permanente une miniature de playlist
• Hashtags et liens à appui long
• Mode d'affichage de la carte
diff --git a/fastlane/metadata/android/fr/changelogs/995.txt b/fastlane/metadata/android/fr/changelogs/995.txt
index f8b55f3fd..b91f83875 100644
--- a/fastlane/metadata/android/fr/changelogs/995.txt
+++ b/fastlane/metadata/android/fr/changelogs/995.txt
@@ -13,4 +13,4 @@ Corrigé
• Correction des fenêtres contextuelles et des plantages du lecteur
• Sélection de mauvaises langues dans le sélecteur de langue
• Le focus audio du lecteur ne respectait pas la fonction muet
-• L'ajout d'éléments de liste de lecture ne fonctionnait parfois pas
+• L'ajout d'éléments de playlist ne fonctionnait parfois pas
diff --git a/fastlane/metadata/android/fr/changelogs/997.txt b/fastlane/metadata/android/fr/changelogs/997.txt
index 87ca55570..b1a550577 100644
--- a/fastlane/metadata/android/fr/changelogs/997.txt
+++ b/fastlane/metadata/android/fr/changelogs/997.txt
@@ -1,7 +1,7 @@
Nouveau
• Ajouter des réponses aux commentaires
-• Autoriser la réorganisation des listes de lecture
-• Afficher la description et la durée de la liste de lecture
+• Autoriser la réorganisation des playlists
+• Afficher la description et la durée de la playlist
• Autoriser la réinitialisation des paramètres
Amélioré
diff --git a/fastlane/metadata/android/hi/changelogs/1000.txt b/fastlane/metadata/android/hi/changelogs/1000.txt
index 67a819e0f..201a8a970 100644
--- a/fastlane/metadata/android/hi/changelogs/1000.txt
+++ b/fastlane/metadata/android/hi/changelogs/1000.txt
@@ -7,7 +7,3 @@
• RSS बटन दृश्यता को ठीक करें
• सीकबार पूर्वावलोकन क्रैश को ठीक करें
• थंबनेल-रहित आइटम को प्लेलिस्ट में डालना ठीक करें
-• डाउनलोड डायलॉग के दिखाई देने से पहले बाहर निकलने को ठीक करें
-• संबंधित आइटम सूची एनक्यू पॉपअप को ठीक करें
-• प्लेलिस्ट में जोड़ें डायलॉग में क्रम को ठीक करें
-• प्लेलिस्ट बुकमार्क आइटम लेआउट को समायोजित करें
diff --git a/fastlane/metadata/android/hi/changelogs/1002.txt b/fastlane/metadata/android/hi/changelogs/1002.txt
index d780f47a6..a0bc033fe 100644
--- a/fastlane/metadata/android/hi/changelogs/1002.txt
+++ b/fastlane/metadata/android/hi/changelogs/1002.txt
@@ -1,5 +1,4 @@
YouTube द्वारा कोई भी स्ट्रीम न चलाए जाने की समस्या को ठीक किया गया।
यह रिलीज़ केवल सबसे ज़्यादा दबाव वाली त्रुटि को संबोधित करती है जो YouTube वीडियो विवरण को लोड होने से रोकती है।
-
हम जानते हैं कि अन्य समस्याएँ भी हैं, और हम जल्द ही उन्हें हल करने के लिए एक अलग रिलीज़ जारी करेंगे।
diff --git a/fastlane/metadata/android/hi/changelogs/1004.txt b/fastlane/metadata/android/hi/changelogs/1004.txt
index 071ab64e3..faf98d116 100644
--- a/fastlane/metadata/android/hi/changelogs/1004.txt
+++ b/fastlane/metadata/android/hi/changelogs/1004.txt
@@ -1 +1,3 @@
-फिक्स्ड YouTube कोई स्ट्रीम नहीं चला रहा है
+इस रिलीज़ में YouTube सिर्फ़ 360p स्ट्रीम दे रहा था, इसे ठीक किया गया है।
+
+ध्यान दें कि इस वर्शन में इस्तेमाल किया गया सॉल्यूशन शायद टेम्पररी है, और लंबे समय में SABR वीडियो प्रोटोकॉल को लागू करने की ज़रूरत है, लेकिन TeamNewPipe के सदस्य अभी बिज़ी हैं, इसलिए किसी भी मदद की बहुत तारीफ़ होगी! https://github.com/TeamNewPipe/NewPipe/issues/12248
diff --git a/fastlane/metadata/android/hi/changelogs/1005.txt b/fastlane/metadata/android/hi/changelogs/1005.txt
index 495894e76..4d72dc68f 100644
--- a/fastlane/metadata/android/hi/changelogs/1005.txt
+++ b/fastlane/metadata/android/hi/changelogs/1005.txt
@@ -1,17 +1,15 @@
नया
-+ • Android Auto के लिए समर्थन जोड़ें
-+ • फ़ीड समूहों को मुख्य स्क्रीन टैब के रूप में सेट करने की अनुमति दें
-+ • [YouTube] अस्थायी प्लेलिस्ट के रूप में साझा करें
-+ • [SoundCloud] "पसंद" चैनल टैब जोङी गई
+• Android Auto के लिए समर्थन जोड़ें
+• फ़ीड समूहों को मुख्य स्क्रीन टैब के रूप में सेट करने की अनुमति दें
+• [YouTube] अस्थायी प्लेलिस्ट के रूप में साझा करें
+• [SoundCloud] "पसंद" चैनल टैब जोङी गई
बेहतर किए
-+ • खोज बार संकेत
-+ • डाउनलोडस स्क्रीन में डाउनलोड की तारीख दिखाएं
-+ • Android 13+ पर प्रति-ऐप भाषा का उपयोग करें
+• खोज बार संकेत
+• डाउनलोडस स्क्रीन में डाउनलोड की तारीख दिखाएं
+• Android 13+ पर प्रति-ऐप भाषा का उपयोग करें
फिक्स किए
-+ • डार्क मोड में पाठ के रंग ठीक करें
-+ • [YouTube] 100 से अधिक आइटम लोड नहीं करने वाली प्लेलिस्ट को ठीक करें
-+ • [YouTube] अनुपलब्ध अनुशंसित वीडियो को ठीक करें
-+ • इतिहास सूची दृश्य में क्रैश ठीक करें
-+ • टिप्पणी के उत्तरों में टाइमस्टैम्प को ठीक करें
+• डार्क मोड में पाठ के रंग ठीक करें
+• [YouTube] 100 से अधिक आइटम लोड नहीं करने वाली प्लेलिस्ट को ठीक करें
+• टिप्पणी के उत्तरों में टाइमस्टैम्प को ठीक करें
diff --git a/fastlane/metadata/android/hi/changelogs/1006.txt b/fastlane/metadata/android/hi/changelogs/1006.txt
new file mode 100644
index 000000000..4545d60ed
--- /dev/null
+++ b/fastlane/metadata/android/hi/changelogs/1006.txt
@@ -0,0 +1,10 @@
+# बेहतर किए
+टाइमस्टैम्प पर क्लिक करते समय मौजूदा प्लेयर पर ही दिखाएं
+जब हो सके तो पेंडिंग डाउनलोड मिशन को रिकवर करने की कोशिश करें
+फ़ाइल डिलीट किए बिना डाउनलोड डिलीट करने का ऑप्शन जोड़ें
+.soundcloud लिंक खोलने में सपोर्ट करें
+
+7 से कम Android वर्शन के लिए छोटे नंबर फ़ॉर्मेटिंग को ठीक किया गया
+खाली नोटिफ़िकेशन को ठीक किया गया
+SRT सबटाइटल फ़ाइलों के लिए ठीक किया गया
+कई क्रैश ठीक किए गए
diff --git a/fastlane/metadata/android/hi/changelogs/65.txt b/fastlane/metadata/android/hi/changelogs/65.txt
index d2c2b8c71..d870f8d03 100644
--- a/fastlane/metadata/android/hi/changelogs/65.txt
+++ b/fastlane/metadata/android/hi/changelogs/65.txt
@@ -1,26 +1,13 @@
### सुधार
-- बर्गरमेनू आइकन एनीमेशन को अक्षम करें #1486
-- डाउनलोड को पूर्ववत करें #1472
-- शेयर मेनू में डाउनलोड विकल्प #1498
-- लॉन्ग टैप मेनू में शेयर विकल्प जोड़ा गया #1454
-- बाहर निकलने पर मुख्य प्लेयर को छोटा करें #1354
-- लाइब्रेरी संस्करण अपडेट और डेटाबेस बैकअप फिक्स #1510
-- एक्सोप्लेयर 2.8.2 अपडेट #1392
-- तेज गति परिवर्तन के लिए विभिन्न चरण आकारों का समर्थन करने के लिए प्लेबैक गति नियंत्रण संवाद को फिर से तैयार किया गया।
-- प्लेबैक गति नियंत्रण में मौन के दौरान तेजी से आगे बढ़ने के लिए एक टॉगल जोड़ा गया। यह ऑडियोबुक और कुछ संगीत शैलियों के लिए मददगार होना चाहिए, और एक सच्चा सहज अनुभव ला सकता है (और बहुत सारे मौन वाले गीत को तोड़ सकता है =\\)।
-- मीडिया स्रोत रिज़ॉल्यूशन को फिर से तैयार किया गया ताकि प्लेयर में आंतरिक रूप से मीडिया के साथ मेटाडेटा को पास किया जा सके, बजाय मैन्युअल रूप से ऐसा करने के। अब हमारे पास मेटाडेटा का एक ही स्रोत है और प्लेबैक शुरू होने पर सीधे उपलब्ध है।
-- जब प्लेलिस्ट का टुकड़ा खोला जाता है तो नया मेटाडेटा उपलब्ध होने पर रिमोट प्लेलिस्ट मेटाडेटा अपडेट नहीं होता है।
-- विभिन्न UI फ़िक्सेस: #1383, बैकग्राउंड प्लेयर नोटिफिकेशन कंट्रोल अब हमेशा सफ़ेद रहता है, फ़्लिंगिंग के ज़रिए पॉपअप प्लेयर को बंद करना आसान है
-- मल्टीसर्विस के लिए रीफ़ैक्टर्ड आर्किटेक्चर के साथ नए एक्सट्रैक्टर का उपयोग करें
+- बर्गरमेनू आइकन एनिमेशन को डिसेबल करें #1486
+- डाउनलोड को अनडू करें #1472
+- शेयर मेनू में डाउनलोड ऑप्शन #1498
+- लॉन्ग टैप मेनू में शेयर ऑप्शन जोड़ा गया #1454
+- ExoPlayer 2.8.2 अपडेट #1392
+- कई UI फ़िक्स: #1383
-### फ़िक्सेस
+### फ़िक्स
-- फ़िक्स #1440 टूटी हुई वीडियो जानकारी लेआउट #1491
- व्यू हिस्ट्री फ़िक्स #1497
-- #1495, जैसे ही उपयोगकर्ता प्लेलिस्ट एक्सेस करता है मेटाडेटा (थंबनेल, शीर्षक और वीडियो काउंट) को अपडेट करके।
-- #1475, जब उपयोगकर्ता डिटेल फ़्रैगमेंट पर बाहरी प्लेयर पर वीडियो शुरू करता है तो डेटाबेस में व्यू रजिस्टर करके।
-- पॉपअप मोड के मामले में स्क्रीन टाइमआउट को ठीक करें। #1463 (फ़िक्स #640)
-- मुख्य वीडियो प्लेयर फ़िक्स #1509
-- [#1412] प्लेयर गतिविधि के बैकग्राउंड में होने पर नया इंटेंट प्राप्त होने पर प्लेयर NPE का कारण बनने वाले रिपीट मोड को ठीक किया गया।
-- पॉपअप के लिए प्लेयर को छोटा करने की सुविधा को ठीक किया गया, जब पॉपअप की अनुमति नहीं दी जाती है तो प्लेयर नष्ट नहीं होता है।
+- #1495, जैसे ही यूज़र प्लेलिस्ट एक्सेस करता है, मेटाडेटा (थंबनेल, टाइटल और वीडियो काउंट) को अपडेट करके।
diff --git a/fastlane/metadata/android/hi/changelogs/66.txt b/fastlane/metadata/android/hi/changelogs/66.txt
index 30c20b0e8..e9ec1e3fa 100644
--- a/fastlane/metadata/android/hi/changelogs/66.txt
+++ b/fastlane/metadata/android/hi/changelogs/66.txt
@@ -1,33 +1,21 @@
-# Changelog of v0.13.7
+# v0.13.7 का चेंजलॉग
-### Fixed
-- Fix sort filter issues of v0.13.6
+### ठीक किया गया
+- v0.13.6 के सॉर्ट फ़िल्टर की दिक्कतें ठीक की गईं
-# Changelog of v0.13.6
+# v0.13.6 का चेंजलॉग
-### Improvements
+### सुधार
-- Disable burgermenu icon animation #1486
-- undo delete of downloads #1472
-- Download option in share menu #1498
-- Added share option to long tap menu #1454
-- Minimize main player on exit #1354
-- Library version update and database backup fix #1510
-- ExoPlayer 2.8.2 Update #1392
- - Reworked the playback speed control dialog to support different step sizes for faster speed change.
- - Added a toggle to fast-forward during silences in playback speed control. This should be helpful for audiobooks and certain music genres, and can bring a true seamless experience (and can break a song with lots of silences =\\).
- - Refactored media source resolution to allow passing metadata alongside media internally in the player, rather than doing so manually. Now we have a single source of metadata and is directly available when playback starts.
- - Fixed remote playlist metadata not updating when new metadata is available when playlist fragment is opened.
- - Various UI fixes: #1383, background player notification controls now always white, easier to shutdown popup player through flinging
-- Use new extractor with refactored architecture for multiservice
+- बर्गरमेनू आइकन एनिमेशन डिसेबल करें #1486
+- डाउनलोड को अनडू डिलीट करें #1472
+- शेयर मेनू में डाउनलोड ऑप्शन #1498
+- लॉन्ग टैप मेनू में शेयर ऑप्शन जोड़ा गया #1454
+- ExoPlayer 2.8.2 अपडेट #1392
+कई UI फ़िक्स: #1383
-### Fixes
+### फ़िक्स
-- Fix #1440 Broken Video Info Layout #1491
-- View history fix #1497
- - #1495, by updating the metadata (thumbnail, title and video count) as soon as the user access the playlist.
- - #1475, by registering a view in the database when the user starts a video on external player on detail fragment.
-- Fix creen timeout in case of popup mode. #1463 (Fixed #640)
-- Main video player fix #1509
- - [#1412] Fixed repeat mode causing player NPE when new intent is received while player activity is in background.
- - Fixed minimizing player to popup does not destroy player when popup permission is not granted.
+- फ़िक्स #1440 टूटा हुआ वीडियो इन्फ़ो लेआउट #1491
+- व्यू हिस्ट्री फ़िक्स #1497
+- मेन वीडियो प्लेयर फिक्स #1509।
diff --git a/fastlane/metadata/android/hi/changelogs/68.txt b/fastlane/metadata/android/hi/changelogs/68.txt
index 238b1e0b1..f0cc5bddb 100644
--- a/fastlane/metadata/android/hi/changelogs/68.txt
+++ b/fastlane/metadata/android/hi/changelogs/68.txt
@@ -1,31 +1,19 @@
-# changes of v0.14.1
+# v0.14.1 में बदलाव
-### Fixed
-- Fixed failed to decrypt video url #1659
-- Fixed description link not extract well #1657
+### ठीक किया गया
+- वीडियो URL डिक्रिप्ट करने में फेल होना ठीक किया गया #1659
+- डिस्क्रिप्शन लिंक ठीक से एक्सट्रेक्ट नहीं हो रहा था, इसे ठीक किया गया #1657
-# changes of v0.14.0
+# v0.14.0 में बदलाव
-### New
-- New Drawer design #1461
-- New customizable front page #1461
+### नया
+- नया ड्रॉअर डिज़ाइन #1461
+- नया कस्टमाइज़ेबल फ्रंट पेज #1461
-### Improvements
-- Reworked Gesture controls #1604
-- New way to close the popup player #1597
+### सुधार
+- पॉपअप प्लेयर बंद करने का नया तरीका #1597
-### Fixed
-- Fix error when subscription count is not available. Closes #1649.
- - Show "Subscriber count not available" in those cases
-- Fix NPE when a YouTube playlist is empty
-- Quick fix for the kiosks in SoundCloud
-- Refactor and bugfix #1623
- - Fix Cyclic search result #1562
- - Fix Seek bar not statically lay outed
- - Fix YT Premium video are not blocked correctly
- - Fix Videos sometimes not loading (due to DASH parsing)
- - Fix links in video description
- - Show warning when someone tries to download to external sdcard
- - fix nothing shown exception triggers report
- - thumbnail not shown in background player for android 8.1 [see here](https://github.com/TeamNewPipe/NewPipe/issues/943)
-- Fix registering of broadcast receiver. Closes #1641.
+### ठीक किया गया
+- जब YouTube प्लेलिस्ट खाली हो तो NPE को ठीक करें
+- SoundCloud में कियोस्क के लिए क्विक फिक्स
+- रीफैक्टर और बगफिक्स #1623।
diff --git a/fastlane/metadata/android/hi/changelogs/69.txt b/fastlane/metadata/android/hi/changelogs/69.txt
index c8262d1b0..8bdf96c8f 100644
--- a/fastlane/metadata/android/hi/changelogs/69.txt
+++ b/fastlane/metadata/android/hi/changelogs/69.txt
@@ -1,19 +1,15 @@
-### New
-- Long-tap delete and share in subscriptions #1516
-- Tablet UI and grid list layout #1617
+### नया
+- सब्सक्रिप्शन में लंबे समय तक टैप करके डिलीट और शेयर करें #1516
+- टैबलेट UI और ग्रिड लिस्ट लेआउट #1617
-### Improvements
-- store and reload the last used aspect ratio #1748
-- Enable linear layout in Downloads activity with full video names #1771
-- Delete and share subscriptions directly from within the subscriptions tab #1516
-- Enqueuing now triggers video playing if the play queue has already ended #1783
-- Separate settings for volume and brightness gestures #1644
-- Add support for Localization #1792
+### सुधार
+- वॉल्यूम और ब्राइटनेस जेस्चर के लिए अलग सेटिंग्स #1644
+- लोकलाइज़ेशन के लिए सपोर्ट जोड़ें #1792
-### Fixes
-- Fix time parsing for . format, so NewPipe can be used in Finland
-- Fix subscription count
-- Add foreground service permission for API 28+ devices #1830
+### सुधार
+- . फ़ॉर्मेट के लिए टाइम पार्सिंग ठीक करें, ताकि फ़िनलैंड में NewPipe का इस्तेमाल किया जा सके
+- सब्सक्रिप्शन काउंट ठीक करें
+- API 28+ डिवाइस के लिए फ़ोरग्राउंड सर्विस परमिशन जोड़ें #1830
-### Known Bugs
-- Playback state can not be saved on Android P
+### जाने-पहचाने बग
+- Android P पर प्लेबैक स्टेट सेव नहीं किया जा सकता
diff --git a/fastlane/metadata/android/hi/changelogs/70.txt b/fastlane/metadata/android/hi/changelogs/70.txt
index ad87a4409..cfa334bdb 100644
--- a/fastlane/metadata/android/hi/changelogs/70.txt
+++ b/fastlane/metadata/android/hi/changelogs/70.txt
@@ -1,25 +1,11 @@
-ATTENTION: This version probably is a bugfest, just like the last one. However due to the full shutdown since the 17. a broken version is better then no version. Right? ¯\_(ツ)_/¯
+### सुधार
+* डाउनलोड की गई फ़ाइलें अब एक क्लिक से खोली जा सकती हैं #1879
+* एंड्रॉयड 4.1 - 4.3 के लिए सपोर्ट हटा दिया गया #1884
+* पुराना प्लेयर हटाएँ #1884
+* मौजूदा प्ले क्यू से स्ट्रीम को दाईं ओर स्वाइप करके हटाएँ #1915
+* बहुत सारी डाउनलोड गड़बड़ियाँ ठीक करके सुधार किया गए
-### Improvements
-* downloaded files can now be opened with one click #1879
-* drop support for android 4.1 - 4.3 #1884
-* remove old player #1884
-* remove streams from current play queue by swiping them to the right #1915
-* remove auto queued stream when a new stream is enqueued manually #1878
-* Postprocessing for downloads and implement missing features #1759 by @kapodamy
- * Post-processing infrastructure
- * Proper error handling "infrastructure" (for downloader)
- * Queue instead of multiple downloads
- * Move serialized pending downloads (`.giga` files) to app data
- * Implement max download retry
- * Proper multi-thread download pausing
- * Stop downloads when swicthing to mobile network (never works, see 2nd point)
- * Save the thread count for next downloads
- * A lot of incoherences fixed
-
-### Fixed
-* Fix crash with default resolution set to best and limited mobile data resolution #1835
-* pop-up player crash fixed #1874
-* NPE when trying to open background player #1901
-* Fix for inserting new streams when auto queuing is enabled #1878
-* Fixed the decypering shuttown issue
+### ठीक किया गया
+* डिफ़ॉल्ट रिज़ॉल्यूशन को बेस्ट और लिमिटेड मोबाइल डेटा रिज़ॉल्यूशन पर सेट करने पर क्रैश को ठीक किया गया #1835
+* पॉप-अप प्लेयर क्रैश को ठीक किया गया #1874
+* बैकग्राउंड प्लेयर खोलने की कोशिश करते समय NPE #1901
diff --git a/fastlane/metadata/android/hi/changelogs/71.txt b/fastlane/metadata/android/hi/changelogs/71.txt
index 5facfc05f..c9b9675b0 100644
--- a/fastlane/metadata/android/hi/changelogs/71.txt
+++ b/fastlane/metadata/android/hi/changelogs/71.txt
@@ -1,10 +1,7 @@
-### Improvements
-* Add app update notification for GitHub build (#1608 by @krtkush)
-* Various improvements to the downloader (#1944 by @kapodamy):
- * add missing white icons and use hardcored way for change the icon colors
- * check if the iterator is initialized (fixes #2031)
- * allow retry downloads with "post-processing failed" error in the new muxer
- * new MPEG-4 muxer fixing non-synchronous video and audio streams (#2039)
+### सुधार
+* GitHub बिल्ड के लिए ऐप अपडेट नोटिफ़िकेशन जोड़ें (#1608 @krtkush द्वारा)
+* डाउनलोडर में कई सुधार #1944
+* नया MPEG-4 म्यूक्सर नॉन-सिंक्रोनस वीडियो और ऑडियो स्ट्रीम को ठीक करता है (#2039)
-### Fixed
-* YouTube live streams stop playing after a short time (#1996 by @yausername)
+### फिकसड
+* YouTube लाइव स्ट्रीम थोड़े समय बाद चलना बंद हो जाती हैं (#1996 @yausername द्वारा)
diff --git a/fastlane/metadata/android/hi/changelogs/740.txt b/fastlane/metadata/android/hi/changelogs/740.txt
index c795978a8..9380af1b0 100644
--- a/fastlane/metadata/android/hi/changelogs/740.txt
+++ b/fastlane/metadata/android/hi/changelogs/740.txt
@@ -1,23 +1,12 @@
-Improvements
+सुधार
-- make links in comments clickable, increase text size
-- seek on clicking timestamp links in comments
-- show preferred tab based on recently selected state
-- add playlist to queue when long clicking on 'Background' in playlist window
-- search for shared text when it is not an URL
-- add "share at current time" button to the main video player
-- add close button to main player when video queue is finished
-- add "Play directly in Background" to longpress menu for video list items
-- improve English translations for Play/Enqueue commands
-- small performance improvements
-- remove unused files
-- update ExoPlayer to 2.9.6
-- add support for Invidious links
-
-Fixed
+कमेंट्स में लिंक को क्लिक करने लायक बनाएं, टेक्स्ट का साइज़ बढ़ाएं
+कमेंट्स में टाइमस्टैम्प लिंक पर क्लिक करने पर खोजें
+जब शेयर किया गया टेक्स्ट URL न हो तो उसे खोजें
+मेन वीडियो प्लेयर में "अभी के समय शेयर करें" बटन जोड़ें
+ExoPlayer को 2.9.6 पर अपडेट करना
+फिकसड
+
-- fixed scroll w/ comments and related streams disabled
-- fixed CheckForNewAppVersionTask being executed when it shouldn't
-- fixed youtube subscription import: ignore ones with invalid url and keep ones with empty title
-- fix invalid YouTube url: signature tag name is not always "signature" preventing streams from loading
+- गलत YouTube URL ठीक करें: सिग्नेचर टैग का नाम हमेशा "सिग्नेचर" नहीं होता, जिससे स्ट्रीम लोड नहीं हो पातीं
diff --git a/fastlane/metadata/android/hi/changelogs/750.txt b/fastlane/metadata/android/hi/changelogs/750.txt
index 39b77f7c3..13e965311 100644
--- a/fastlane/metadata/android/hi/changelogs/750.txt
+++ b/fastlane/metadata/android/hi/changelogs/750.txt
@@ -1,22 +1,13 @@
-New
-Playback resume #2288
-• Resume streams where you stopped last time
-Downloader Enhancements #2149
-• Use Storage Access Framework to store downloads on external SD-cards
-• New mp4 muxer
-• Optionally change the download directory before starting a download
-• Respect metered networks
+नया
+प्लेबैक फिर से शुरू करें #2288
+• स्ट्रीम वहीं से फिर से शुरू करें जहाँ आपने पिछली बार रोका था
+डाउनलोडर एन्हांसमेंट #2149
+• एक्सटर्नल SD-कार्ड पर डाउनलोड स्टोर करने के लिए स्टोरेज एक्सेस फ्रेमवर्क का इस्तेमाल करें
+बेहतर
+• एक्टिविटी लाइफसाइकल के दौरान (ऑटो) रोटेशन में बदलाव को हैंडल करें #2444
+• लॉन्ग-प्रेस मेनू को एक जैसा बनाएं #2368
-Improved
-• Removed gema strings #2295
-• Handle (auto)rotation changes during activity lifecycle #2444
-• Make long-press menus consistent #2368
-
-Fixed
-• Fixed selected subtitle track name not being shown #2394
-• Do not crash when check for app update fails (GitHub version) #2423
-• Fixed downloads stuck at 99.9% #2440
-• Update play queue metadata #2453
-• [SoundCloud] Fixed crash when loading playlists TeamNewPipe/NewPipeExtractor#170
-• [YouTube] Fixed duration can not be paresd TeamNewPipe/NewPipeExtractor#177
+ठीक किया गया
+• चुने हुए सबटाइटल ट्रैक का नाम नहीं दिखना ठीक किया गया #2394
+• 99.9% पर अटके डाउनलोड को ठीक किया गया #2440
diff --git a/fastlane/metadata/android/hi/changelogs/760.txt b/fastlane/metadata/android/hi/changelogs/760.txt
index 6e000f6d9..c4b6d951f 100644
--- a/fastlane/metadata/android/hi/changelogs/760.txt
+++ b/fastlane/metadata/android/hi/changelogs/760.txt
@@ -1,43 +1,13 @@
-Changes in 0.17.1
+0.17.1 में बदलाव
-New
-• Thai localization
+नया
+• थाई लोकलाइज़ेशन
+बेहतर
+• प्लेलिस्ट के लिए लॉन्ग-प्रेस मेनू में फिर से 'यहाँ से प्ले करना शुरू करें' एक्शन जोड़ें #2518
+• SAF / लेगेसी फ़ाइल पिकर के लिए स्विच जोड़ें #2521
-Improved
-• Add start playing here action in long-press menus for playlists again #2518
-• Add switch for SAF / legacy file picker #2521
-
-Fixed
-• Fix disappearing buttons in downloads view when switching apps #2487
-• Fix playback position is stored although watch history is disabled
-• Fix reduced performance caused by playback position in list views #2517
-• [Extractor] Fix ReCaptchaActivity #2527, TeamNewPipe/NewPipeExtractor#186
-• [Extractor] [YouTube] Fix casual search error when playlists are in results TeamNewPipe/NewPipeExtractor#185
-
-
-
-Changes in 0.17.0
-
-New
-Playback resume #2288
-• Resume streams where you stopped last time
-Downloader Enhancements #2149
-• Use Storage Access Framework to store downloads on external SD-cards
-• New mp4 muxer
-• Optionally change the download directory before starting a download
-• Respect metered networks
-
-
-Improved
-• Removed gema strings #2295
-• Handle (auto)rotation changes during activity lifecycle #2444
-• Make long-press menus consistent #2368
-
-Fixed
-• Fixed selected subtitle track name not being shown #2394
-• Do not crash when check for app update fails (GitHub version) #2423
-• Fixed downloads stuck at 99.9% #2440
-• Update play queue metadata #2453
-• [SoundCloud] Fixed crash when loading playlists TeamNewPipe/NewPipeExtractor#170
-• [YouTube] Fixed duration can not be paresd TeamNewPipe/NewPipeExtractor#177
+ठीक किया गया
+• ऐप बदलते समय डाउनलोड व्यू में बटन गायब होने की समस्या ठीक करें #2487
+• लिस्ट व्यू में प्लेबैक पोज़िशन की वजह से परफॉर्मेंस में आई कमी को ठीक करें #2517
+• [एक्सट्रैक्टर] [YouTube] जब प्लेलिस्ट रिज़ल्ट में हों तो कैज़ुअल सर्च एरर को ठीक करें TeamNewPipe/NewPipeExtractor#185
diff --git a/fastlane/metadata/android/hi/changelogs/790.txt b/fastlane/metadata/android/hi/changelogs/790.txt
index ec77b2acb..3b322f0af 100644
--- a/fastlane/metadata/android/hi/changelogs/790.txt
+++ b/fastlane/metadata/android/hi/changelogs/790.txt
@@ -1,14 +1,9 @@
-Improved
-• Add more titles to improve accessibility for blind people #2655
-• Make language of download folder setting more consistent and less ambiguous #2637
+ठीक किया गया
+• चेक करें कि ब्लॉक में आखिरी बाइट डाउनलोड हुआ है या नहीं #2646
+• वीडियो डिटेल फ़्रैगमेंट में स्क्रॉलिंग को ठीक किया गया #2672
+• [साउंडक्लाउड] client_id एक्सट्रैक्शन को ठीक करें #2745
-Fixed
-• Check if last byte in the block is downloaded #2646
-• Fixed scrolling in video detail fragment #2672
-• Remove double search clear box animations to one #2695
-• [SoundCloud] Fix client_id extraction #2745
-
-Development
-• Add missing dependencies inherited from NewPipeExtractor into NewPipe #2535
-• Migrate to AndroidX #2685
-• Update to ExoPlayer 2.10.6 #2697, #2736
+डेवलपमेंट
+• NewPipeExtractor से मिली गायब डिपेंडेंसी को NewPipe में जोड़ें #2535
+• AndroidX पर माइग्रेट करें #2685
+• ExoPlayer 2.10.6 पर अपडेट करें #2697, #2736
diff --git a/fastlane/metadata/android/hi/changelogs/800.txt b/fastlane/metadata/android/hi/changelogs/800.txt
index 332b5c994..4df518086 100644
--- a/fastlane/metadata/android/hi/changelogs/800.txt
+++ b/fastlane/metadata/android/hi/changelogs/800.txt
@@ -1,27 +1,10 @@
-New
-• PeerTube support without P2P (#2201) [Beta]:
- ◦ Watch and download videos from PeerTube instances
- ◦ Add instances in the settings to access the complete PeerTube world
- ◦ There might be problems with SSL handshakes on Android 4.4 and 7.1 when accessing certain instances resulting in a network error.
+नया
+• P2P के बिना PeerTube सपोर्ट (#2201) [बीटा]:
-• Downloader (#2679):
- ◦ Calculate download ETA
- ◦ Download opus (webm files) as ogg
- ◦ Recover expired download links to resume downloads after a long pause
+◦ लंबे समय तक रुकने के बाद डाउनलोड फिर से शुरू करने के लिए एक्सपायर हो चुके डाउनलोड लिंक रिकवर करें
-Improved
-• Make the KioskFragment aware of changes in the preferred content country and improve performance of all main tabs #2742
-• Use new Localization and Downloader implementations from extractor #2713
-• Make "Default kiosk" string translatable
-• Black navigation bar for black theme #2569
+बेहतर
+• KioskFragment को पसंदीदा कंटेंट देश में होने वाले बदलावों के बारे में बताएं और सभी मेन टैब की परफॉर्मेंस को बेहतर बनाएं #2742
-Fixed
-• Fixed a bug that could not move the popup player if another finger was placed while moving the popup player #2772
-• Allow playlists missing an uploader and fix crashes related to this problem #2724, TeamNewPipe/NewPipeExtractor#219
-• Enabling TLS1.1/1.2 on Android 4.4 devices (API 19/KitKat) to fix TLS handshake with MediaCCC and some PeerTube instances #2792
-• [SoundCloud] Fixed client_id extraction TeamNewPipe/NewPipeExtractor#217
-• [SoundCloud] Fix audio stream extraction
-
-Development
-• Update ExoPlayer to 2.10.8 #2791, #2816
-• Update Gradle to 3.5.1 and add Kotlin support #2714
+फिक्स किया गया
+• Android 4.4 डिवाइस (API 19/KitKat) पर TLS1.1/1.2 इनेबल करें
diff --git a/fastlane/metadata/android/hi/changelogs/810.txt b/fastlane/metadata/android/hi/changelogs/810.txt
index c75855fd1..b3d4c7bd6 100644
--- a/fastlane/metadata/android/hi/changelogs/810.txt
+++ b/fastlane/metadata/android/hi/changelogs/810.txt
@@ -1,19 +1,11 @@
-New
-• Show video thumbnail on the lock screen when playing in the background
+नया
+• बैकग्राउंड में चलने पर लॉक स्क्रीन पर वीडियो थंमनेल दिखाएं
-Improved
-• Add local playlist to queue when long pressing on background / popup button
-• Make main page tabs scrollable and hide when there is only a single tab
-• Limit amount of notification thumbnail updates in background player
-• Add dummy thumbnail for empty local playlists
-• Use *.opus file extension instead of *.webm and show "opus" in format label instead of "WebM Opus" in the download dropdown
-• Add button to delete downloaded files or download history in "Downloads"
-• [YouTube] Add support to /c/shortened_url channel links
+बेहतर
+• बैकग्राउंड / पॉपअप बटन पर देर तक दबाने पर लोकल प्लेलिस्ट को क्यू में जोड़ें
+• [YouTube] /c/shortened_url चैनल लिंक के लिए सपोर्ट जोड़ें
-Fixed
-• Fixed multiple issues when sharing a video to NewPipe and downloading its streams directly
-• Fixed player access out of its creation thread
-• Fixed search result paging
-• [YouTube] Fixed switching on null causing NPE
-• [YouTube] Fixed viewing comments when opening an invidio.us url
-• [SoundCloud] Updated client_id
+फिकसड
+• NewPipe पर वीडियो शेयर करते समय और सीधे उसकी स्ट्रीम डाउनलोड करते समय कई दिक्कतें ठीक की गईं
+• सर्च रिज़ल्ट पेजिंग ठीक की गई
+• [SoundCloud] client_id अपडेट किया गया
diff --git a/fastlane/metadata/android/hi/changelogs/840.txt b/fastlane/metadata/android/hi/changelogs/840.txt
index 95dc80844..5be8a8660 100644
--- a/fastlane/metadata/android/hi/changelogs/840.txt
+++ b/fastlane/metadata/android/hi/changelogs/840.txt
@@ -1,22 +1,10 @@
-New
-• Added language selector to change the app language
-• Added send to Kodi button to player collapsible menu
-• Added ability to copy comments on long press
+नया
+• ऐप की भाषा बदलने के लिए भाशा सिलेक्टर जोड़ा गया
+• प्लेयर कोलैप्सिबल मेनू में कोडी को भेजें बटन जोड़ा गया
+• देर तक दबाने पर कमेंट्स कॉपी करने की सुविधा जोड़ी गई
-Improved
-• Fix ReCaptcha activity and correctly save obtained cookies
-• Removed dot-menu in favour of drawer and hide history button when watch history is not enabled in settings
-• Ask for display over other apps permission in settings correctly on Android 6 and later
-• Rename local playlist by long-clicking in BookmarkFragment
-• Various PeerTube improvements
-• Improved several English source strings
+बेहतर
+• ReCaptcha एक्टिविटी को ठीक किया गया और मिली हुई कुकीज़ को सही ढंग से सेव किया गया
-Fixed
-• Fixed player starting again although it is paused when option "minimize on app switch" enabled and NewPipe is minimized
-• Fix initial brightness value for gesture
-• Fixed .srt subtitle downloads containing not all line breaks
-• Fixed download to SD card failing because some Android 5 devices are not CTF compliant
-• Fixed downloading on Android KitKat
-• Fixed corrupt video .mp4 file being recognized as audio file
-• Fixed multiple localization problems, including wrong Chinese language codes
-• [YouTube] Timestamps in description are clickable again
+ठीक किया गया
+• Android KitKat पर डाउनलोडिंग ठीक की गई
diff --git a/fastlane/metadata/android/hi/changelogs/930.txt b/fastlane/metadata/android/hi/changelogs/930.txt
index b23b01ea8..457d1745b 100644
--- a/fastlane/metadata/android/hi/changelogs/930.txt
+++ b/fastlane/metadata/android/hi/changelogs/930.txt
@@ -1,19 +1,13 @@
-New
-• Search on YouTube Music
-• Basic Android TV support
+नया
+• YouTube Music पर सर्च करें
+• बेसिक Android TV सपोर्ट
-Improved
-• Added the ability to remove all watched videos from a local playlist
-• Show message when content isn't supported yet instead of crashing
-• Improved popup player resize with pinch gestures
-• Enqueue streams on long press on background and popup buttons in channel
-• Improved size handling of the drawer header title
+बेहतर
+• लोकल प्लेलिस्ट से सभी देखे गए वीडियो हटाने की सुविधा जोड़ी गई
+• जब कंटेंट अभी सपोर्टेड न हो, तो क्रैश होने के बजाय मैसेज दिखाएं
-Fixed
-• Fixed age restricted content setting not working
-• Fixed certain kinds of reCAPTCHAs
-• Fixed crash when opening bookmarks while playlist is `null`
-• Fixed detection of network related exceptions
-• Fixed visibility of group sort button in the subscriptions fragment
+फिकसड
+• उम्र पर रोक वाली कंटेंट सेटिंग काम नहीं कर रही थी, इसे ठीक किया गया
+• कुछ तरह के reCAPTCHA को ठीक किया गया
-and more
+और भी बहुत कुछ
diff --git a/fastlane/metadata/android/hi/changelogs/940.txt b/fastlane/metadata/android/hi/changelogs/940.txt
index f9530bc68..6f9253a2f 100644
--- a/fastlane/metadata/android/hi/changelogs/940.txt
+++ b/fastlane/metadata/android/hi/changelogs/940.txt
@@ -1,16 +1,14 @@
-New
-• Add support for SoundCloud comments
-• Add YouTube restricted mode setting
-• Show PeerTube parent channel details
+नया
+• SoundCloud कमेंट्स के लिए सपोर्ट जोड़ें
+• YouTube रेस्ट्रिक्टेड मोड सेटिंग जोड़ें
+• PeerTube पेरेंट चैनल की डिटेल्स दिखाएँ
-Improved
-• Show Kore button only for supported services
-• Block player gestures that begin at the NavigationBar or StatusBar
-• Change retry & subscribe buttons background color based on service color
+बेहतर
+• सिर्फ़ सपोर्टेड सर्विसेज़ के लिए Kore बटन दिखाएँ
-Fixed
-• Fix download dialog freeze
-• Open in browser button now really opens in browser
-• Fix crash on opening videos and "Could not play this stream"
+फिक्स किया गया
+• डाउनलोड डायलॉग फ़्रीज़ होने की समस्या को ठीक करें
+• ब्राउज़र में खोलें बटन अब सच में ब्राउज़र में खुलता है
+• वीडियो खोलने पर क्रैश और "यह स्ट्रीम नहीं चला सका"
-and more
+और भी बहुत कुछ
diff --git a/fastlane/metadata/android/hi/changelogs/951.txt b/fastlane/metadata/android/hi/changelogs/951.txt
index e933e5cbd..ffc1f8891 100644
--- a/fastlane/metadata/android/hi/changelogs/951.txt
+++ b/fastlane/metadata/android/hi/changelogs/951.txt
@@ -1,17 +1,13 @@
-New
-• Add search for subscription picker in the feed group dialog
-• Add filter to the feed group dialog to show only ungrouped subscriptions
-• Add playlist tab to main page
-• Fast forward/rewind in background/pop-up player queue
-• Display search suggestion: did you mean & showing result for
+नया
+• फ़ीड ग्रुप डायलॉग में सब्सक्रिप्शन पिकर के लिए सर्च जोड़ें
+• फ़ीड ग्रुप डायलॉग में फ़िल्टर जोड़ें ताकि सिर्फ़ अनग्रुप्ड सब्सक्रिप्शन दिखें
+• मेन पेज पर प्लेलिस्ट टैब जोड़ें
-Improved
-• Drop writing application metadata in muxed files
-• Do not remove failed streams from the queue
-• Update status bar color to match toolbar color
+बेहतर
+• म्यूक्स की गई फ़ाइलों में एप्लीकेशन मेटाडेटा लिखना बंद करें
+• फ़ेल स्ट्रीम को क्यू से न हटाएं
-Fixed
-• Fixed audio/video desync caused by floating point cumulative errors
-• [PeerTube] Handle deleted comments
+फिकसड
+• फ़्लोटिंग पॉइंट क्यूमुलेटिव एरर के कारण होने वाले ऑडियो/वीडियो डीसिंक को ठीक किया गया
-and more
+और भी बहुत कुछ
diff --git a/fastlane/metadata/android/hi/changelogs/995.txt b/fastlane/metadata/android/hi/changelogs/995.txt
index 63ed335a4..7bd7341c2 100644
--- a/fastlane/metadata/android/hi/changelogs/995.txt
+++ b/fastlane/metadata/android/hi/changelogs/995.txt
@@ -1,16 +1,14 @@
नया
• चैनल टैब्स का समर्थन करें
• छवि गुणवत्ता का चयन करें
-• सभी छवियों के यूआरएल प्राप्त करें
सुधार किए
• प्लेयर इंटरफ़ेस की पहुंच
• केवल-वीडियो डाउनलोड के लिए बेहतर ऑडियो चयन
-• साझा प्लेलिस्ट सामग्री में प्लेलिस्ट और वीडियो नाम शामिल करने का विकल्प
ठीक किए
• [यूट्यूब] लाइक पाने की संख्या ठीक करें
• पॉपअप और क्रैश पर प्रतिक्रिया नहीं देने वाले प्लेयर को ठीक करें
• भाषा चयनकर्ता में गलत भाषाओं का चयन ठीक करें
• प्लेयर ऑडियो फोकस म्यूट का सम्मान नहीं कर रहा था
-• प्लेलिस्ट में आइटम जोड़ना कभी-कभी काम नहीं कर रहा था
+• प्लेलिस्ट में आइटम ना जुड़ना ठीक किया
diff --git a/fastlane/metadata/android/hi/changelogs/997.txt b/fastlane/metadata/android/hi/changelogs/997.txt
index 652935884..b47816231 100644
--- a/fastlane/metadata/android/hi/changelogs/997.txt
+++ b/fastlane/metadata/android/hi/changelogs/997.txt
@@ -6,12 +6,9 @@
सुधार
• [एंड्रॉइड 13+] कस्टम अधिसूचना क्रियाएं पुनर्स्थापित करें
-• अपडेटस की जांच के लिए सहमति का अनुरोध करें
-• बफ़रिंग के दौरान नोटीफिकेशन से चलाने/रोकने की अनुमति दें
• कुछ सेटिंग्स पुनः व्यवस्थित करें
ठीक किए
• [यूट्यूब] लोड न होने वाली टिप्पणियों को ठीक करें, साथ ही अन्य फिक्स और सुधार भी
-• सेटिंग्स आयात में भेद्यता को हल करें और JSON पर स्विच करें
• विभिन्न डाउनलोड सुधार
• खोज पाठ को ट्रिम करें
diff --git a/fastlane/metadata/android/hu/changelogs/1006.txt b/fastlane/metadata/android/hu/changelogs/1006.txt
new file mode 100644
index 000000000..a5cbf76eb
--- /dev/null
+++ b/fastlane/metadata/android/hu/changelogs/1006.txt
@@ -0,0 +1,13 @@
+# Továbbfejlesztve
+Az aktuális lejátszó megmarad időbélyegre kattintáskor
+Függőben lévő letöltések helyreállításának megkísérlése
+Letöltés törlése a fájl megtartásával
+Overlay engedélyhez magyarázó párbeszédablak (Android 11+)
+on.soundcloud hivatkozások támogatása
+Sok kisebb fejlesztés és optimalizálás
+
+# Javítva
+Számozás javítása Android 7 alatt
+Szellem értesítések javítása
+SRT felirat javítások
+Sok összeomlás javítva
diff --git a/fastlane/metadata/android/id/changelogs/1005.txt b/fastlane/metadata/android/id/changelogs/1005.txt
new file mode 100644
index 000000000..885f25ddb
--- /dev/null
+++ b/fastlane/metadata/android/id/changelogs/1005.txt
@@ -0,0 +1,17 @@
+Baru
+• Dukungan untuk Android Auto
+• Grup umpan sebagai tab layar utama
+• [YouTube] Bagikan sebagai daftar putar sementara
+• [SoundCloud] Tab saluran suka
+
+Ditingkatkan
+• Petunjuk bilah pencarian lebih baik
+• Tanggal unduhan di Unduhan
+• Bahasa per aplikasi Android 13
+
+Diperbaiki
+• Warna teks rusak di mode gelap
+• [YouTube] Daftar putar tidak lebih dari 100 item
+• [YouTube] Video rekomendasi hilang
+• Kerusakan di tampilan Riwayat
+• Cap waktu dalam balasan komentar
diff --git a/fastlane/metadata/android/it/changelogs/1006.txt b/fastlane/metadata/android/it/changelogs/1006.txt
new file mode 100644
index 000000000..f7cbbf868
--- /dev/null
+++ b/fastlane/metadata/android/it/changelogs/1006.txt
@@ -0,0 +1,16 @@
+# Migliorie
+Tieni il player attuale se si cliccano le marche temporali
+Recupera i download in sospeso se possibile
+Opzione per eliminare un download senza anche eliminare il file
+Autorizzazione di sovrapposizione: mostra finestra esplicativa per Android > R
+Supporto per link on.soundcloud
+Tanti piccoli miglioramenti e ottimizzazioni
+
+# Correzioni
+Formattazione breve del conto per Android < 7
+Notifiche fantasma
+File di sottotitoli SRT
+Crash vari
+
+# Sviluppo
+Ammodernamento del codice interno
diff --git a/fastlane/metadata/android/ka/changelogs/1000.txt b/fastlane/metadata/android/ka/changelogs/1000.txt
new file mode 100644
index 000000000..c59dcdbd0
--- /dev/null
+++ b/fastlane/metadata/android/ka/changelogs/1000.txt
@@ -0,0 +1,12 @@
+გაუმჯობესებულია
+• დასაკრავი სიის აღწერა დაწკაპუნებით გახდა შესაძლებელი მეტი/ნაკლები კონტენტის საჩვენებლად
+• [PeerTube] `subscribeto.me` ეგზემპლარის ბმულების ავტომატურად დამუშავება
+• ისტორიის ეკრანზე მხოლოდ ერთი ერთეულის დაკვრა იწყება
+გამოსწორებულია
+• RSS ღილაკის ხილვადობის გამოსწორება
+• ძიების ზოლის გადახედვის შეცდომის გამოსწორება
+• გამოსწორდა დასაკრავი სიის მინიატურების გარეშე ელემენტის პრობლემა
+• გამოსწორდა ჩამოტვირთვის დიალოგური ფანჯრის გამოჩენამდე გამორთვის პრობლემა
+• დაკავშირებული ერთეულების სიის რიგში ჩასმის ამომხტარი ფანჯარა გამოსწორდა
+• დასაკრავ სიაში დამატების დიალოგში თანმიმდევრობა გამოსწორდა
+• დასაკრავი სიის სანიშნეების ელემენტის განლაგების კორექტირება
diff --git a/fastlane/metadata/android/ka/changelogs/1001.txt b/fastlane/metadata/android/ka/changelogs/1001.txt
new file mode 100644
index 000000000..63574fa11
--- /dev/null
+++ b/fastlane/metadata/android/ka/changelogs/1001.txt
@@ -0,0 +1,5 @@
+გაუმჯობესებულია
+• Android 13+-ზე მოთამაშის შეტყობინებების პარამეტრების შეცვლის ყოველთვის დაშვება
+გამოსწორებულია
+• გამოსწორდა მონაცემთა ბაზის/გამოწერების ექსპორტირებისას არსებული ფაილის შეკვეცა, რამაც შესაძლოა ექსპორტის დაზიანება გამოიწვიოს.
+• დროის ნიშნულზე გამოსწორდა დაწკაპუნებისას მოთამაშის თავიდან განახლება
diff --git a/fastlane/metadata/android/ka/changelogs/1002.txt b/fastlane/metadata/android/ka/changelogs/1002.txt
new file mode 100644
index 000000000..5b2eb01a8
--- /dev/null
+++ b/fastlane/metadata/android/ka/changelogs/1002.txt
@@ -0,0 +1,4 @@
+გამოსწორდა YouTube-ის არცერთი სტრიმინგის ჩატვირთვის პრობლემა.
+
+ეს ვერსია მხოლოდ ყველაზე აქტუალურ შეცდომას აგვარებს, რომელიც YouTube ვიდეოს დეტალების ჩატვირთვას ხელს უშლიდა.
+ჩვენ ვიცით, რომ არსებობს სხვა პრობლემებიც და მალე გამოვაქვეყნებთ ცალკე ვერსიას მათ გადასაჭრელად.
diff --git a/fastlane/metadata/android/ka/changelogs/1003.txt b/fastlane/metadata/android/ka/changelogs/1003.txt
new file mode 100644
index 000000000..209362e25
--- /dev/null
+++ b/fastlane/metadata/android/ka/changelogs/1003.txt
@@ -0,0 +1,6 @@
+ეს არის ცხელი შესწორების ვერსია, რომელიც ასწორებს YouTube-ის შეცდომებს:
+• [YouTube] გამოსწორდა ვიდეოს ინფორმაციის ჩატვირთვის შეუძლებლობა, გამოსწორდა HTTP 403 შეცდომები ვიდეოების დაკვრის დროს და აღდგა ასაკობრივი შეზღუდვის მქონე ზოგიერთი ვიდეოს დაკვრა
+• გამოსწორდა სუბტიტრების ზომის შეუცვლელობა
+• გამოსწორდა ინფორმაციის ორჯერ ჩამოტვირთვის პრობლემა ნაკადის გახსნისას
+• [Soundcloud] წაიშალა დაუკრავი DRM-ით დაცული ნაკადები
+• განახლდა თარგმანები
diff --git a/fastlane/metadata/android/ka/changelogs/1004.txt b/fastlane/metadata/android/ka/changelogs/1004.txt
index d20512f17..31f488a16 100644
--- a/fastlane/metadata/android/ka/changelogs/1004.txt
+++ b/fastlane/metadata/android/ka/changelogs/1004.txt
@@ -1 +1,3 @@
-გაასწორა YouTube არ უკრავს არცერთ ნაკადს
+ეს ვერსია ასწორებს YouTube-ი აჩვებებს მხოლოდ 360p სტრიმინგის პრობლემას.
+
+გაითვალისწინეთ, რომ ამ ვერსიაში გამოყენებული გადაწყვეტა, სავარაუდოდ, დროებითია და გრძელვადიან პერსპექტივაში SABR ვიდეო პროტოკოლის დანერგვაა საჭირო, თუმცა TeamNewPipe-ის წევრები ამჟამად დაკავებულები არიან, ამიტომ ნებისმიერი დახმარება დიდად დასაფასებელი იქნება! https://github.com/TeamNewPipe/NewPipe/issues/12248
diff --git a/fastlane/metadata/android/ka/changelogs/1005.txt b/fastlane/metadata/android/ka/changelogs/1005.txt
new file mode 100644
index 000000000..e08f2639f
--- /dev/null
+++ b/fastlane/metadata/android/ka/changelogs/1005.txt
@@ -0,0 +1,15 @@
+ახალი
+• დაემატა Android Auto-ს მხარდაჭერა
+• არხების ჯგუფების მთავარი ეკრანის ჩანართებად დაყენების დაშვება
+• [YouTube] გაზიარება, როგორც დროებითი დასაკრავი სია
+• [SoundCloud] მოწონებების არხის ჩანართი
+გაუმჯობესებულია
+• უკეთესი მინიშნებები ძიების ზოლში
+• ჩამოტვირთვის თარიღის ჩვენება ჩამოტვირთვებში
+• Android 13-ის თითოეული აპლიკაციის ენის გამოყენება
+.გამოსწორებულია
+• გამოსწორდა ტექსტის ფერების დარღვევა ბნელ რეჟიმში
+• [YouTube] გამოსწორდა დასაკრავი სიების 100-ზე მეტი ერთეულს არ აჩვენებს
+• [YouTube] გამოსწორდა დაკარგული რეკომენდებული ვიდეოები
+• გამოსწორდა ისტორიის სიის ხედში ავარიების გამოსწორება
+• გამოსწორდა დროის ნიშნულები კომენტარების პასუხებში
diff --git a/fastlane/metadata/android/ka/changelogs/63.txt b/fastlane/metadata/android/ka/changelogs/63.txt
index 185bfd650..76d878325 100644
--- a/fastlane/metadata/android/ka/changelogs/63.txt
+++ b/fastlane/metadata/android/ka/changelogs/63.txt
@@ -1,8 +1,7 @@
### გაუმჯობესებები
- - იმპორტი/ექსპორტის პარამეტრები #1333
- - ზედრევის შემცირება (შესრულების გაუმჯობესება) #1371
- - მცირე კოდის გაუმჯობესება #1375
- - დაამატეთ ყველაფერი GDPR #1420-ის შესახებ
-
- ### გამოსწორდა
- - Downloader: შეასწორეთ ავარია დაუმთავრებელი ჩამოტვირთვების ჩატვირთვისას .giga ფაილებიდან #1407
+- იმპორტის/ექსპორტის პარამეტრები #1333
+- ზედმეტად დიდი მოცულობის შეცდომის შემცირება (შესრულების გაუმჯობესება) #1371
+- კოდის მცირე გაუმჯობესებები #1375
+- GDPR-ის შესახებ ყველაფრის დამატება #1420
+### გამოსწორებულია
+- ჩამომტვირთავი: გამოასწორეთ შეცდომის პრობლემა .giga ფაილებიდან დაუმთავრებელი ჩამოტვირთვების ჩატვირთვისას#1407
diff --git a/fastlane/metadata/android/ka/changelogs/65.txt b/fastlane/metadata/android/ka/changelogs/65.txt
new file mode 100644
index 000000000..8ddbda2b7
--- /dev/null
+++ b/fastlane/metadata/android/ka/changelogs/65.txt
@@ -0,0 +1,23 @@
+### გაუმჯობესებები
+- ბურგერის მენიუს ხატულას ანიმაციის გამორთვა #1486
+- ჩამოტვირთვების წაშლის გაუქმების ღილაკი #1472
+- ჩამოტვირთვის ღილაკი გაზიარების მენიუში #1498
+- ხანგრძლივი შეხების მენიუში #1454 დაემატა გაზიარების ღილაკი
+- მთავარი პლეერის მინიმიზაცია გასვლისას #1354
+- ბიბლიოთეკის ვერსიის განახლება და მონაცემთა ბაზის სარეზერვო ასლის შესწორება #1510
+- ExoPlayer 2.8.2 განახლება #1392
+- გადამუშავდა დაკვრის სიჩქარის კონტროლის დიალოგი, რათა მხარდაჭერილიყო სხვადასხვა ნაბიჯების ზომები სიჩქარის უფრო სწრაფი ცვლილებისთვის.
+- დაკვრის სიჩქარის კონტროლში დაემატა გადამრთველი სიჩუმის დროს წინ გადასართავად. ეს უნდა იყოს სასარგებლო აუდიოწიგნებისა და გარკვეული მუსიკალური ჟანრებისთვის და შეიძლება უზრუნველყოს ჭეშმარიტად შეუფერხებელი გამოცდილება (და შეიძლება დაარღვიოს სიმღერა, რომელსაც ბევრი სიჩუმე აქვს =\\).
+- გადაკეთდა მედია წყაროს გარჩევადობა, რათა მეტამონაცემების გადაცემა მედიასთან ერთად პლეერში შიდა რეჟიმში მოხდეს, ხელით გაკეთების ნაცვლად. ახლა ჩვენ გვაქვს მეტამონაცემების ერთი წყარო და ის პირდაპირ ხელმისაწვდომია დაკვრის დაწყებისას.
+ - გამოსწორდა დისტანციური დასაკრავი სიის მეტამონაცემების განახლება, როდესაც ახალი მეტამონაცემები ხელმისაწვდომია დასაკრავი სიის ფრაგმენტის გახსნისას.
+- სხვადასხვა ინტერფეისის გამოსწორება: #1383, ფონური პლეერის შეტყობინებების კონტროლი ახლა ყოველთვის თეთრია, უფრო ადვილია ამომხტარი პლეერის გამორთვა გადახვევით.
+- გამოიყენეთ ახალი ექსტრაქტორი განახლებული არქიტექტურით მრავალსერვისისთვის.
+### გამოსწორებები
+- გამოსწორდა #1440 ვიდეო ინფორმაციის გაფუჭებული განლაგება #1491
+- გამოსწორდა ნახვის ისტორია#1497
+- #1495, მეტამონაცემების (მინიატურების, სათაურის და ვიდეოების რაოდენობის) განახლებით, როგორც კი მომხმარებელი წვდება დასაკრავ სიას.
+- #1475, ხედვის რეგისტრაციით მონაცემთა ბაზაში, როდესაც მომხმარებელი იწყებს ვიდეოს გარე პლეერზე დეტალების ფრაგმენტზე.
+- გამოსწორდა ეკრანის დროის ამოწურვა ამომხტარი რეჟიმის შემთხვევაში. #1463 (გამოსწორდა #640)
+- მთავარი ვიდეო პლეერის გამოსწორება #1509
+- [#1412] გამოსწორდა გამეორების რეჟიმი, რომელიც იწვევდა პლეერის NPE-ს, როდესაც ახალი განზრახვა მიიღება, როდესაც მოთამაშის აქტივობა ფონურ რეჟიმშია.
+ - გამოსწორდა მოთამაშის ამომხტარ ფანჯარაში მინიმიზაციის შეცდომა, როდესაც ამომხტარ ფანჯარაში ნებართვა არ არის მინიჭებული.
diff --git a/fastlane/metadata/android/ka/changelogs/996.txt b/fastlane/metadata/android/ka/changelogs/996.txt
new file mode 100644
index 000000000..7da3ca0ed
--- /dev/null
+++ b/fastlane/metadata/android/ka/changelogs/996.txt
@@ -0,0 +1,2 @@
+media.ccc.de-ზე არხის/კონფერენციის გახსნისას გამოსწორდა NullPointerException.
+გრინჩმა სცადა თქვენთვის საშობაო საჩუქრის გატეხვა, მაგრამ ჩვენ გამოვასწორეთ.
diff --git a/fastlane/metadata/android/ko/changelogs/1000.txt b/fastlane/metadata/android/ko/changelogs/1000.txt
new file mode 100644
index 000000000..d2f5bf58a
--- /dev/null
+++ b/fastlane/metadata/android/ko/changelogs/1000.txt
@@ -0,0 +1,13 @@
+개선됨 (Improved)
+• 재생목록 설명을 클릭하여 더 보기 / 간단히 보기 전환 가능
+• [PeerTube] `subscribeto.me` 인스턴스 링크 자동 처리
+• 기록 화면에서 단일 항목만 재생 시작
+
+수정됨 (Fixed)
+• RSS 버튼 표시 문제 수정
+• 탐색바 미리보기 충돌 수정
+• 썸네일이 없는 항목 재생목록 추가 문제 수정
+• 다운로드 대화상자가 나타나기 전에 종료되는 문제 수정
+• 관련 항목 목록의 대기열 팝업 수정
+• 재생목록에 추가 대화상자의 순서 문제 수정
+• 재생목록 북마크 항목 레이아웃 조정
diff --git a/fastlane/metadata/android/ko/changelogs/1006.txt b/fastlane/metadata/android/ko/changelogs/1006.txt
new file mode 100644
index 000000000..1729e9827
--- /dev/null
+++ b/fastlane/metadata/android/ko/changelogs/1006.txt
@@ -0,0 +1,16 @@
+# 개선됨
+타임스탬프를 클릭할 때 현재 플레이어를 유지합니다.
+가능한 경우 보류 중인 다운로드 미션을 복구하세요.
+파일 삭제 없이 다운로드를 삭제하는 옵션을 추가하세요.
+오버레이 권한: Android > R에 대한 설명 대화 상자 표시
+사운드클라우드 링크 열기 지원
+많은 작은 개선과 최적화
+
+# 고정
+7 이하의 안드로이드 버전에 대한 짧은 숫자 형식을 수정하세요.
+고스트 알림 수정
+SRT 자막 파일 수정
+고정된 수많은 충돌 사고
+
+# 개발
+내부 코드 현대화
diff --git a/fastlane/metadata/android/pa/changelogs/1000.txt b/fastlane/metadata/android/pa/changelogs/1000.txt
index 90d70c151..ddc239f32 100644
--- a/fastlane/metadata/android/pa/changelogs/1000.txt
+++ b/fastlane/metadata/android/pa/changelogs/1000.txt
@@ -3,11 +3,9 @@
• [PeerTube] `subscribeto.me` ਇੰਸਟੈਂਸ ਲਿੰਕਾਂ ਨੂੰ ਆਟੋਮੈਟਿਕ ਹੀ ਹੈਂਡਲ ਕਰੋ
• ਇਤਿਹਾਸ ਸਕਰੀਨ ਵਿੱਚ ਸਿਰਫ਼ ਸਿੰਗਲ ਆਈਟਮ ਨੂੰ ਚਲਾਉਣਾ ਸ਼ੁਰੂ ਕਰੋ
-ਠੀਕ ਕਰਿਆ
+ਫਿਕਸਡ
• RSS ਬਟਨ ਦੀ ਦਿੱਖ ਨੂੰ ਠੀਕ ਕਰੋ
• ਸੀਕਬਾਰ ਪੂਰਵਦਰਸ਼ਨ ਕ੍ਰੈਸ਼ਾਂ ਨੂੰ ਠੀਕ ਕਰੋ
• ਥੰਮਨੇਲ-ਰਹਿਤ ਆਈਟਮ ਦੀ ਪਲੇਲਿਸਟਿੰਗ ਨੂੰ ਠੀਕ ਕਰੋ
-• ਡਾਉਨਲੋਡ ਡਾਇਲਾਗ ਦੇ ਦਿਸਣ ਤੋਂ ਪਹਿਲਾਂ ਇਸਨੂੰ ਬਾਹਰ ਕੱਢਣਾ ਠੀਕ ਕਰੋ
-• ਸੰਬੰਧਿਤ ਆਈਟਮਾਂ ਦੀ ਸੂਚੀ ਐਨਕਿਊ ਪੌਪਅੱਪ ਨੂੰ ਠੀਕ ਕਰੋ
-• ਪਲੇਲਿਸਟ ਡਾਇਲਾਗ ਵਿੱਚ ਜੋੜਨ ਦਾ ਕ੍ਰਮ ਠੀਕ ਕਰੋ
-• ਪਲੇਲਿਸਟ ਬੁੱਕਮਾਰਕ ਆਈਟਮ ਖਾਕਾ ਵਿਵਸਥਿਤ ਕਰੋ
+• ਸੰਬੰਧਿਤ ਆਈਟਮਾਂ ਦੀ ਸੂਚੀ ਐਨਕਿਊ ਪੌਪ-ਅਪ ਨੂੰ ਠੀਕ ਕਰੋ
+• ਅਤੇ ਹੋਰ ਪਲੇਲਿਸਟ ਤੇ ਡਾਊਨਲੋਡ ਸਬੰਧਤ ਫਿਕਸ
diff --git a/fastlane/metadata/android/pa/changelogs/1004.txt b/fastlane/metadata/android/pa/changelogs/1004.txt
index fe62a1330..6d3d23b2e 100644
--- a/fastlane/metadata/android/pa/changelogs/1004.txt
+++ b/fastlane/metadata/android/pa/changelogs/1004.txt
@@ -1 +1,3 @@
-ਸਥਿਰ YouTube ਕੋਈ ਸਟ੍ਰੀਮ ਨਹੀਂ ਚਲਾ ਰਿਹਾ
+ਇਹ ਰੀਲੀਜ਼ ਸਿਰਫ਼ 360p ਸਟ੍ਰੀਮ ਪ੍ਰਦਾਨ ਕਰਨ ਵਾਲੇ YouTube ਨੂੰ ਠੀਕ ਕਰਦੀ ਹੈ।
+
+ਧਿਆਨ ਦਿਓ ਕਿ ਇਸ ਸੰਸਕਰਣ ਵਿੱਚ ਵਰਤਿਆ ਗਿਆ ਹੱਲ ਸੰਭਾਵਤ ਤੌਰ 'ਤੇ ਅਸਥਾਈ ਹੈ, ਅਤੇ ਲੰਬੇ ਸਮੇਂ ਵਿੱਚ SABR ਵੀਡੀਓ ਪ੍ਰੋਟੋਕੋਲ ਨੂੰ ਲਾਗੂ ਕਰਨ ਦੀ ਜ਼ਰੂਰਤ ਹੈ, ਪਰ TeamNewPipe ਮੈਂਬਰ ਇਸ ਸਮੇਂ ਰੁੱਝੇ ਹੋਏ ਹਨ ਇਸ ਲਈ ਕਿਸੇ ਵੀ ਮਦਦ ਦੀ ਬਹੁਤ ਪ੍ਰਸ਼ੰਸਾ ਕੀਤੀ ਜਾਵੇਗੀ! https://github.com/TeamNewPipe/NewPipe/issues/12248
diff --git a/fastlane/metadata/android/pa/changelogs/1005.txt b/fastlane/metadata/android/pa/changelogs/1005.txt
index f1492a1ac..982b092a4 100644
--- a/fastlane/metadata/android/pa/changelogs/1005.txt
+++ b/fastlane/metadata/android/pa/changelogs/1005.txt
@@ -1,17 +1,10 @@
ਨਵਾਂ
-+ • Android Auto ਲਈ ਸਮਰਥਨ ਸ਼ਾਮਿਲ ਕਰੋ
-+ • ਫੀਡ ਗਰੁੱਪਾਂ ਨੂੰ ਮੁੱਖ ਸਕ੍ਰੀਨ ਟੈਬਾਂ ਵਜੋਂ ਸੈੱਟ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ
-+ • [YouTube] ਅਸਥਾਈ ਪਲੇਲਿਸਟ ਦੇ ਵਜੋਂ ਸਾਂਝਾ ਕਰੋ
-+ • [SoundCloud] "ਪਸੰਦ" ਚੈਨਲ ਟੈਬ ਜੋੜੀ ਗਈ
-
-ਬਿਹਤਰ ਕੀਤੇ
-+ • ਖੋਜ ਬਾਰ ਸੰਕੇਤ
-+ • ਡਾਊਨਲੋਡਸ ਸੂਚੀ ਵਿੱਚ ਡਾਊਨਲੋਡ ਤਾਰੀਖ ਦਿਖਾਓ
-+ • ਐਂਡਰਾਇਡ 13+ 'ਤੇ ਪ੍ਰਤੀ ਐਪ ਭਾਸ਼ਾ ਦੀ ਵਰਤੋਂ ਕਰੋ
+• Android Auto ਲਈ ਸਮਰਥਨ ਸ਼ਾਮਿਲ ਕਰਨ ਸਮੇਤ YouTube ਲਈ ਅਸਥਾਈ ਪਲੇਲਿਸਟ ਵਜੋਂ ਸ਼ੇਅਰ ਫੰਕਸ਼ਨ ਤੇ SoundCloud ਲਈ ਲਾਈਕਸ ਚੈਨਲ ਟੈਬ ਨਵੀਂ ਐਡ ਕੀਤੀ
+• ਫੀਡ ਗਰੁੱਪਾਂ ਨੂੰ ਮੁੱਖ ਸਕ੍ਰੀਨ ਟੈਬਾਂ ਵਜੋਂ ਸੈੱਟ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ
ਦਰੁਸਤ ਕੀਤੇ
-+ • ਡਾਰਕ ਥੀਮਾਂ 'ਤੇ ਟੈਕਸਟ ਰੰਗਾਂ ਨੂੰ ਠੀਕ ਕਰੋ
-+ • [YouTube] ਪਲੇਲਿਸਟਾਂ ਨੂੰ ਠੀਕ ਕਰੋ ਜੋ 100 ਤੋਂ ਵੱਧ ਆਈਟਮਾਂ ਲੋਡ ਨਹੀਂ ਕਰਦੀਆਂ
-+ • [YouTube] ਸਿਫਾਰਸ਼ ਕੀਤੀਆਂ ਵੀਡੀਓਜ਼ ਦੀ ਅਣਉਪਲੱਬਧਤਾ ਨੂੰ ਠੀਕ ਕਰੋ
-+ • ਇਤਿਹਾਸ ਸੂਚੀ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਕ੍ਰੈਸ਼ ਨੂੰ ਠੀਕ ਕਰੋ
-+ • ਟਿੱਪਣੀਆਂ ਦੇ ਜਵਾਬ ਵਿੱਚ ਟਾਈਮਸਟੈਂਪਾਂ ਨੂੰ ਠੀਕ ਕਰੋ
+• ਡਾਰਕ ਥੀਮਾਂ 'ਤੇ ਟੈਕਸਟ ਰੰਗਾਂ ਨੂੰ ਠੀਕ ਕਰੋ
+• [YouTube] ਪਲੇਲਿਸਟਾਂ ਨੂੰ ਠੀਕ ਕਰੋ ਜੋ 100 ਤੋਂ ਵੱਧ ਆਈਟਮਾਂ ਲੋਡ ਨਹੀਂ ਕਰਦੀਆਂ
+• [YouTube] ਸਿਫਾਰਸ਼ ਕੀਤੀਆਂ ਵੀਡੀਓਜ਼ ਦੀ ਅਣਉਪਲੱਬਧਤਾ ਨੂੰ ਠੀਕ ਕਰੋ
+• ਟਿੱਪਣੀਆਂ ਦੇ ਜਵਾਬ ਵਿੱਚ ਟਾਈਮਸਟੈਂਪਾਂ ਨੂੰ ਠੀਕ ਕਰੋ
+ਪੂਰੇ ਬਦਲਾਵਾਂ ਵਾਸਤੇ ਗਿਟਹੱਬ ਤੇ dev ਸ਼ਾਖਾ ਟੈਗ ਅਨੁਸਾਰ ਬਦਲਾਅ ਵੇਖੋ
diff --git a/fastlane/metadata/android/pa/changelogs/1006.txt b/fastlane/metadata/android/pa/changelogs/1006.txt
new file mode 100644
index 000000000..5046eaaa0
--- /dev/null
+++ b/fastlane/metadata/android/pa/changelogs/1006.txt
@@ -0,0 +1,9 @@
+# ਸੁਧਾਰਿਆ ਗਿਆ
+ਟਾਈਮਸਟੈਂਪਾਂ 'ਤੇ ਕਲਿੱਕ ਕਰਦੇ ਸਮੇਂ ਮੌਜੂਦਾ ਪਲੇਅਰ ਰੱਖੋ
+ਜਦੋਂ ਸੰਭਵ ਹੋਵੇ ਤਾਂ ਬਕਾਇਆ ਡਾਊਨਲੋਡ ਮਿਸ਼ਨਾਂ ਨੂੰ ਮੁੜ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ
+ਫਾਈਲ ਨੂੰ ਮਿਟਾਏ ਬਿਨਾਂ ਡਾਊਨਲੋਡ ਨੂੰ ਮਿਟਾਉਣ ਦਾ ਵਿਕਲਪ ਸ਼ਾਮਿਲ ਕਰੋ
+on.soundcloud ਲਿੰਕ ਖੋਲ੍ਹਣ ਦਾ ਸਮਰਥਨ ਕਰੋ
+7 ਤੋਂ ਘੱਟ ਐਂਡਰਾਇਡ ਸੰਸਕਰਣਾਂ ਲਈ ਛੋਟੀ ਗਿਣਤੀ ਫਾਰਮੈਟਿੰਗ ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ
+ਖਾਲੀ ਨੋਟੀਫਿਕੇਸ਼ਨਾਂ ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ
+SRT ਉਪਸਿਰਲੇਖ ਫਾਈਲਾਂ ਲਈ ਠੀਕ ਕੀਤਾ ਗਿਆ
+ਬਹੁਤ ਸਾਰੇ ਕਰੈਸ਼ ਠੀਕ ਕੀਤੇ ਗਏ
diff --git a/fastlane/metadata/android/pa/changelogs/65.txt b/fastlane/metadata/android/pa/changelogs/65.txt
index 0fbf1147e..0f7f8fe7d 100644
--- a/fastlane/metadata/android/pa/changelogs/65.txt
+++ b/fastlane/metadata/android/pa/changelogs/65.txt
@@ -1 +1,13 @@
-### ਸੁਧਾਰ - ਬਰਗਰਮੇਨੂ ਆਈਕਨ ਐਨੀਮੇਸ਼ਨ #1486 ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਓ - ਡਾਉਨਲੋਡਸ #1472 ਨੂੰ ਮਿਟਾਉਣ ਨੂੰ ਅਨਡੂ ਕਰੋ - ਸ਼ੇਅਰ ਮੀਨੂ #1498 ਵਿੱਚ ਡਾਊਨਲੋਡ ਵਿਕਲਪ - ਲੰਬੇ ਟੈਪ ਮੀਨੂ #1454 ਵਿੱਚ ਸ਼ੇਅਰ ਵਿਕਲਪ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ - ਨਿਕਾਸ #1354 'ਤੇ ਮੁੱਖ ਪਲੇਅਰ ਨੂੰ ਛੋਟਾ ਕਰੋ - ਲਾਇਬ੍ਰੇਰੀ ਸੰਸਕਰਣ ਅਪਡੇਟ ਅਤੇ ਡੇਟਾਬੇਸ ਬੈਕਅਪ ਫਿਕਸ #1510 - ExoPlayer 2.8.2 ਅੱਪਡੇਟ #1392 - ਤੇਜ਼ ਗਤੀ ਤਬਦੀਲੀ ਲਈ ਵੱਖ-ਵੱਖ ਸਟੈਪ ਸਾਈਜ਼ ਦਾ ਸਮਰਥਨ ਕਰਨ ਲਈ ਪਲੇਬੈਕ ਸਪੀਡ ਕੰਟਰੋਲ ਡਾਇਲਾਗ ਨੂੰ ਦੁਬਾਰਾ ਬਣਾਇਆ ਗਿਆ। - ਪਲੇਬੈਕ ਸਪੀਡ ਨਿਯੰਤਰਣ ਵਿੱਚ ਚੁੱਪ ਦੌਰਾਨ ਫਾਸਟ-ਫਾਰਵਰਡ ਕਰਨ ਲਈ ਇੱਕ ਟੌਗਲ ਜੋੜਿਆ ਗਿਆ। ਇਹ ਆਡੀਓਬੁੱਕਾਂ ਅਤੇ ਕੁਝ ਸੰਗੀਤ ਸ਼ੈਲੀਆਂ ਲਈ ਮਦਦਗਾਰ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ, ਅਤੇ ਇੱਕ ਸੱਚਾ ਸਹਿਜ ਅਨੁਭਵ ਲਿਆ ਸਕਦਾ ਹੈ (ਅਤੇ ਬਹੁਤ ਸਾਰੀਆਂ ਚੁੱਪ =\\ ਨਾਲ ਗੀਤ ਤੋੜ ਸਕਦਾ ਹੈ)। - ਹੱਥੀਂ ਅਜਿਹਾ ਕਰਨ ਦੀ ਬਜਾਏ, ਪਲੇਅਰ ਵਿੱਚ ਅੰਦਰੂਨੀ ਤੌਰ 'ਤੇ ਮੀਡੀਆ ਦੇ ਨਾਲ-ਨਾਲ ਮੈਟਾਡੇਟਾ ਪਾਸ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣ ਲਈ ਰੀਫੈਕਟਰਡ ਮੀਡੀਆ ਸਰੋਤ ਰੈਜ਼ੋਲਿਊਸ਼ਨ। ਹੁਣ ਸਾਡੇ ਕੋਲ ਮੈਟਾਡੇਟਾ ਦਾ ਇੱਕ ਸਿੰਗਲ ਸਰੋਤ ਹੈ ਅਤੇ ਪਲੇਬੈਕ ਸ਼ੁਰੂ ਹੋਣ 'ਤੇ ਸਿੱਧਾ ਉਪਲਬਧ ਹੁੰਦਾ ਹੈ। - ਸਥਿਰ ਰਿਮੋਟ ਪਲੇਲਿਸਟ ਮੈਟਾਡੇਟਾ ਅੱਪਡੇਟ ਨਹੀਂ ਹੋ ਰਿਹਾ ਹੈ ਜਦੋਂ ਪਲੇਲਿਸਟ ਫਰੈਗਮੈਂਟ ਖੋਲ੍ਹਿਆ ਜਾਂਦਾ ਹੈ ਤਾਂ ਨਵਾਂ ਮੈਟਾਡੇਟਾ ਉਪਲਬਧ ਹੁੰਦਾ ਹੈ। - ਕਈ UI ਫਿਕਸ: #1383, ਬੈਕਗਰਾਊਂਡ ਪਲੇਅਰ ਨੋਟੀਫਿਕੇਸ਼ਨ ਕੰਟਰੋਲ ਹੁਣ ਹਮੇਸ਼ਾ ਸਫੈਦ, ਫਲਿੰਗਿੰਗ ਰਾਹੀਂ ਪੌਪਅੱਪ ਪਲੇਅਰ ਨੂੰ ਬੰਦ ਕਰਨਾ ਆਸਾਨ - ਮਲਟੀਸਰਵਿਸ ਲਈ ਰੀਫੈਕਟਰਡ ਆਰਕੀਟੈਕਚਰ ਦੇ ਨਾਲ ਨਵੇਂ ਐਕਸਟਰੈਕਟਰ ਦੀ ਵਰਤੋਂ ਕਰੋ ### ਫਿਕਸ - #1440 ਟੁੱਟੇ ਹੋਏ ਵੀਡੀਓ ਜਾਣਕਾਰੀ ਲੇਆਉਟ #1491 ਨੂੰ ਠੀਕ ਕਰੋ - ਇਤਿਹਾਸ ਫਿਕਸ #1497 ਦੇਖੋ - #1495, ਜਿਵੇਂ ਹੀ ਉਪਭੋਗਤਾ ਪਲੇਲਿਸਟ ਤੱਕ ਪਹੁੰਚ ਕਰਦਾ ਹੈ, ਮੈਟਾਡੇਟਾ (ਥੰਬਨੇਲ, ਸਿਰਲੇਖ ਅਤੇ ਵੀਡੀਓ ਗਿਣਤੀ) ਨੂੰ ਅਪਡੇਟ ਕਰਕੇ। - #1475, ਜਦੋਂ ਉਪਭੋਗਤਾ ਵੇਰਵੇ ਦੇ ਟੁਕੜੇ 'ਤੇ ਬਾਹਰੀ ਪਲੇਅਰ 'ਤੇ ਵੀਡੀਓ ਸ਼ੁਰੂ ਕਰਦਾ ਹੈ ਤਾਂ ਡੇਟਾਬੇਸ ਵਿੱਚ ਇੱਕ ਦ੍ਰਿਸ਼ ਨੂੰ ਰਜਿਸਟਰ ਕਰਕੇ। - ਪੌਪਅੱਪ ਮੋਡ ਦੇ ਮਾਮਲੇ ਵਿੱਚ ਕ੍ਰੀਨ ਟਾਈਮਆਊਟ ਫਿਕਸ ਕਰੋ। #1463 (ਸਥਿਰ #640) - ਮੁੱਖ ਵੀਡੀਓ ਪਲੇਅਰ ਫਿਕਸ #1509 - [#1412] ਫਿਕਸਡ ਰੀਪੀਟ ਮੋਡ ਜਿਸ ਨਾਲ ਪਲੇਅਰ ਐਨਪੀਈ ਦਾ ਕਾਰਨ ਬਣਦਾ ਹੈ ਜਦੋਂ ਪਲੇਅਰ ਦੀ ਗਤੀਵਿਧੀ ਬੈਕਗ੍ਰਾਉਂਡ ਵਿੱਚ ਹੁੰਦੀ ਹੈ ਤਾਂ ਨਵਾਂ ਇਰਾਦਾ ਪ੍ਰਾਪਤ ਹੁੰਦਾ ਹੈ। - ਪੌਪਅੱਪ ਲਈ ਫਿਕਸਡ ਮਿਨੀਮਾਈਜ਼ਿੰਗ ਪਲੇਅਰ ਪਲੇਅਰ ਨੂੰ ਨਸ਼ਟ ਨਹੀਂ ਕਰਦਾ ਹੈ ਜਦੋਂ ਪੌਪਅੱਪ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ।
+### ਸੁਧਾਰ
+
+- ਬਰਗਰ ਮੀਨੂ ਆਈਕਨ ਐਨੀਮੇਸ਼ਨ ਨੂੰ ਅਯੋਗ ਕਰੋ #1486
+- ਡਾਊਨਲੋਡਸ ਨੂੰ ਅਨਡੂ ਕਰੋ #1472
+- ਸ਼ੇਅਰ ਮੀਨੂ ਵਿੱਚ ਡਾਊਨਲੋਡ ਵਿਕਲਪ #1498
+- ਲੰਬੇ ਟੈਪ ਮੀਨੂ ਵਿੱਚ ਸਾਂਝਾ ਵਿਕਲਪ ਜੋੜਿਆ ਗਿਆ #1454
+- ਐਕਸੋਪਲੇਅਰ 2.8.2 ਅਪਡੇਟ #1392
+- ਕਈ UI ਫਿਕਸ: #1383
+
+### ਫਿਕਸ
+
+- ਵਿਊ ਹਿਸਟਰੀ ਫਿਕਸ #1497
+- #1495, ਜਿਵੇਂ ਹੀ ਉਪਭੋਗਤਾ ਪਲੇਲਿਸਟ ਤੱਕ ਪਹੁੰਚ ਕਰਦਾ ਹੈ, ਮੈਟਾਡੇਟਾ (ਥੰਬਨੇਲ, ਸਿਰਲੇਖ ਅਤੇ ਵੀਡੀਓ ਗਿਣਤੀ) ਨੂੰ ਅਪਡੇਟ ਕਰਕੇ।
diff --git a/fastlane/metadata/android/pa/changelogs/66.txt b/fastlane/metadata/android/pa/changelogs/66.txt
index aecf80cbc..f400eb137 100644
--- a/fastlane/metadata/android/pa/changelogs/66.txt
+++ b/fastlane/metadata/android/pa/changelogs/66.txt
@@ -1 +1,21 @@
-# v0.13.7 ਦਾ ਚੇਂਜਲਾਗ ### ਸਥਿਰ - v0.13.6 ਦੇ ਕ੍ਰਮਬੱਧ ਫਿਲਟਰ ਮੁੱਦਿਆਂ ਨੂੰ ਠੀਕ ਕਰੋ # v0.13.6 ਦਾ ਚੇਂਜਲਾਗ ### ਸੁਧਾਰ - ਬਰਗਰਮੇਨੂ ਆਈਕਨ ਐਨੀਮੇਸ਼ਨ #1486 ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਓ - ਡਾਉਨਲੋਡਸ #1472 ਨੂੰ ਮਿਟਾਉਣ ਨੂੰ ਅਨਡੂ ਕਰੋ - ਸ਼ੇਅਰ ਮੀਨੂ #1498 ਵਿੱਚ ਡਾਊਨਲੋਡ ਵਿਕਲਪ - ਲੰਬੇ ਟੈਪ ਮੀਨੂ #1454 ਵਿੱਚ ਸ਼ੇਅਰ ਵਿਕਲਪ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ - ਨਿਕਾਸ #1354 'ਤੇ ਮੁੱਖ ਪਲੇਅਰ ਨੂੰ ਛੋਟਾ ਕਰੋ - ਲਾਇਬ੍ਰੇਰੀ ਸੰਸਕਰਣ ਅਪਡੇਟ ਅਤੇ ਡੇਟਾਬੇਸ ਬੈਕਅਪ ਫਿਕਸ #1510 - ExoPlayer 2.8.2 ਅੱਪਡੇਟ #1392 - ਤੇਜ਼ ਗਤੀ ਤਬਦੀਲੀ ਲਈ ਵੱਖ-ਵੱਖ ਸਟੈਪ ਸਾਈਜ਼ ਦਾ ਸਮਰਥਨ ਕਰਨ ਲਈ ਪਲੇਬੈਕ ਸਪੀਡ ਕੰਟਰੋਲ ਡਾਇਲਾਗ ਨੂੰ ਦੁਬਾਰਾ ਬਣਾਇਆ ਗਿਆ। - ਪਲੇਬੈਕ ਸਪੀਡ ਨਿਯੰਤਰਣ ਵਿੱਚ ਚੁੱਪ ਦੌਰਾਨ ਫਾਸਟ-ਫਾਰਵਰਡ ਕਰਨ ਲਈ ਇੱਕ ਟੌਗਲ ਜੋੜਿਆ ਗਿਆ। ਇਹ ਆਡੀਓਬੁੱਕਾਂ ਅਤੇ ਕੁਝ ਸੰਗੀਤ ਸ਼ੈਲੀਆਂ ਲਈ ਮਦਦਗਾਰ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ, ਅਤੇ ਇੱਕ ਸੱਚਾ ਸਹਿਜ ਅਨੁਭਵ ਲਿਆ ਸਕਦਾ ਹੈ (ਅਤੇ ਬਹੁਤ ਸਾਰੀਆਂ ਚੁੱਪ =\\ ਨਾਲ ਗੀਤ ਤੋੜ ਸਕਦਾ ਹੈ)। - ਹੱਥੀਂ ਅਜਿਹਾ ਕਰਨ ਦੀ ਬਜਾਏ, ਪਲੇਅਰ ਵਿੱਚ ਅੰਦਰੂਨੀ ਤੌਰ 'ਤੇ ਮੀਡੀਆ ਦੇ ਨਾਲ-ਨਾਲ ਮੈਟਾਡੇਟਾ ਪਾਸ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣ ਲਈ ਰੀਫੈਕਟਰਡ ਮੀਡੀਆ ਸਰੋਤ ਰੈਜ਼ੋਲਿਊਸ਼ਨ। ਹੁਣ ਸਾਡੇ ਕੋਲ ਮੈਟਾਡੇਟਾ ਦਾ ਇੱਕ ਸਿੰਗਲ ਸਰੋਤ ਹੈ ਅਤੇ ਪਲੇਬੈਕ ਸ਼ੁਰੂ ਹੋਣ 'ਤੇ ਸਿੱਧਾ ਉਪਲਬਧ ਹੁੰਦਾ ਹੈ। - ਸਥਿਰ ਰਿਮੋਟ ਪਲੇਲਿਸਟ ਮੈਟਾਡੇਟਾ ਅੱਪਡੇਟ ਨਹੀਂ ਹੋ ਰਿਹਾ ਹੈ ਜਦੋਂ ਪਲੇਲਿਸਟ ਫਰੈਗਮੈਂਟ ਖੋਲ੍ਹਿਆ ਜਾਂਦਾ ਹੈ ਤਾਂ ਨਵਾਂ ਮੈਟਾਡੇਟਾ ਉਪਲਬਧ ਹੁੰਦਾ ਹੈ। - ਕਈ UI ਫਿਕਸ: #1383, ਬੈਕਗਰਾਊਂਡ ਪਲੇਅਰ ਨੋਟੀਫਿਕੇਸ਼ਨ ਕੰਟਰੋਲ ਹੁਣ ਹਮੇਸ਼ਾ ਸਫੈਦ, ਫਲਿੰਗਿੰਗ ਰਾਹੀਂ ਪੌਪਅੱਪ ਪਲੇਅਰ ਨੂੰ ਬੰਦ ਕਰਨਾ ਆਸਾਨ - ਮਲਟੀਸਰਵਿਸ ਲਈ ਰੀਫੈਕਟਰਡ ਆਰਕੀਟੈਕਚਰ ਦੇ ਨਾਲ ਨਵੇਂ ਐਕਸਟਰੈਕਟਰ ਦੀ ਵਰਤੋਂ ਕਰੋ ### ਫਿਕਸ - #1440 ਟੁੱਟੇ ਹੋਏ ਵੀਡੀਓ ਜਾਣਕਾਰੀ ਲੇਆਉਟ #1491 ਨੂੰ ਠੀਕ ਕਰੋ - ਇਤਿਹਾਸ ਫਿਕਸ #1497 ਦੇਖੋ - #1495, ਜਿਵੇਂ ਹੀ ਉਪਭੋਗਤਾ ਪਲੇਲਿਸਟ ਤੱਕ ਪਹੁੰਚ ਕਰਦਾ ਹੈ, ਮੈਟਾਡੇਟਾ (ਥੰਬਨੇਲ, ਸਿਰਲੇਖ ਅਤੇ ਵੀਡੀਓ ਗਿਣਤੀ) ਨੂੰ ਅਪਡੇਟ ਕਰਕੇ। - #1475, ਜਦੋਂ ਉਪਭੋਗਤਾ ਵੇਰਵੇ ਦੇ ਟੁਕੜੇ 'ਤੇ ਬਾਹਰੀ ਪਲੇਅਰ 'ਤੇ ਵੀਡੀਓ ਸ਼ੁਰੂ ਕਰਦਾ ਹੈ ਤਾਂ ਡੇਟਾਬੇਸ ਵਿੱਚ ਇੱਕ ਦ੍ਰਿਸ਼ ਨੂੰ ਰਜਿਸਟਰ ਕਰਕੇ। - ਪੌਪਅੱਪ ਮੋਡ ਦੇ ਮਾਮਲੇ ਵਿੱਚ ਕ੍ਰੀਨ ਟਾਈਮਆਊਟ ਫਿਕਸ ਕਰੋ। #1463 (ਸਥਿਰ #640) - ਮੁੱਖ ਵੀਡੀਓ ਪਲੇਅਰ ਫਿਕਸ #1509 - [#1412] ਫਿਕਸਡ ਰੀਪੀਟ ਮੋਡ ਜਿਸ ਨਾਲ ਪਲੇਅਰ ਐਨਪੀਈ ਦਾ ਕਾਰਨ ਬਣਦਾ ਹੈ ਜਦੋਂ ਪਲੇਅਰ ਦੀ ਗਤੀਵਿਧੀ ਬੈਕਗ੍ਰਾਉਂਡ ਵਿੱਚ ਹੁੰਦੀ ਹੈ ਤਾਂ ਨਵਾਂ ਇਰਾਦਾ ਪ੍ਰਾਪਤ ਹੁੰਦਾ ਹੈ। - ਪੌਪਅੱਪ ਲਈ ਫਿਕਸਡ ਮਿਨੀਮਾਈਜ਼ਿੰਗ ਪਲੇਅਰ ਪਲੇਅਰ ਨੂੰ ਨਸ਼ਟ ਨਹੀਂ ਕਰਦਾ ਹੈ ਜਦੋਂ ਪੌਪਅੱਪ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ।
+# v0.13.7 ਲਈ ਚੇਂਜਲੌਗ
+
+### ਫਿਕਸ
+- v0.13.6 ਤੋਂ ਸੌਰਟ ਫਿਲਟਰ ਨਾਲ ਸਮੱਸਿਆਵਾਂ ਹੱਲ ਕੀਤੀਆਂ ਗਈਆਂ।
+
+# v0.13.6 ਲਈ ਚੇਂਜਲੌਗ
+
+### ਸੁਧਾਰ
+
+- ਬਰਗਰ ਮੀਨੂ ਆਈਕਨ ਐਨੀਮੇਸ਼ਨ #1486 ਨੂੰ ਅਯੋਗ ਕਰੋ
+- ਡਾਊਨਲੋਡਸ ਨੂੰ ਮਿਟਾਓ ਨੂੰ ਅਣਡੂ ਕਰੋ #1472
+- ਸ਼ੇਅਰ ਮੀਨੂ ਵਿੱਚ ਡਾਊਨਲੋਡ ਵਿਕਲਪ #1498
+- ਲੰਬੇ ਟੈਪ ਮੀਨੂ ਵਿੱਚ ਸ਼ੇਅਰ ਵਿਕਲਪ ਜੋੜਿਆ ਗਿਆ #1454
+- ਐਕਸੋਪਲੇਅਰ 2.8.2 ਅਪਡੇਟ #1392
+ਕਈ UI ਫਿਕਸ: #1383
+
+### ਫਿਕਸ
+
+- ਫਿਕਸ ਕੀਤਾ ਗਿਆ #1440 ਟੁੱਟਿਆ ਹੋਇਆ ਵੀਡੀਓ ਜਾਣਕਾਰੀ ਲੇਆਉਟ #1491
+- ਇਤਿਹਾਸ ਦੇਖੋ ਫਿਕਸ #1497
+- ਮੁੱਖ ਵੀਡੀਓ ਪਲੇਅਰ ਫਿਕਸ #1509.
diff --git a/fastlane/metadata/android/pa/changelogs/68.txt b/fastlane/metadata/android/pa/changelogs/68.txt
index e8e54ea4f..7b98078df 100644
--- a/fastlane/metadata/android/pa/changelogs/68.txt
+++ b/fastlane/metadata/android/pa/changelogs/68.txt
@@ -1 +1,19 @@
-v0.14.1 ਦੇ # ਬਦਲਾਅ ### ਸਥਿਰ - ਵੀਡੀਓ url #1659 ਨੂੰ ਡੀਕ੍ਰਿਪਟ ਕਰਨ ਵਿੱਚ ਅਸਫਲ ਰਿਹਾ - ਸਥਿਰ ਵਰਣਨ ਲਿੰਕ #1657 ਨੂੰ ਚੰਗੀ ਤਰ੍ਹਾਂ ਐਕਸਟਰੈਕਟ ਨਹੀਂ ਕਰਦਾ ਹੈ v0.14.0 ਦੀਆਂ # ਤਬਦੀਲੀਆਂ ### ਨਵਾਂ - ਨਵਾਂ ਦਰਾਜ਼ ਡਿਜ਼ਾਈਨ #1461 - ਨਵਾਂ ਅਨੁਕੂਲਿਤ ਫਰੰਟ ਪੇਜ #1461 ### ਸੁਧਾਰ - ਮੁੜ ਕੰਮ ਕੀਤਾ ਸੰਕੇਤ ਨਿਯੰਤਰਣ #1604 - ਪੌਪਅੱਪ ਪਲੇਅਰ #1597 ਨੂੰ ਬੰਦ ਕਰਨ ਦਾ ਨਵਾਂ ਤਰੀਕਾ ### ਸਥਿਰ - ਗਾਹਕੀ ਦੀ ਗਿਣਤੀ ਉਪਲਬਧ ਨਾ ਹੋਣ 'ਤੇ ਗਲਤੀ ਨੂੰ ਠੀਕ ਕਰੋ। #1649 ਬੰਦ ਹੁੰਦਾ ਹੈ। - ਉਹਨਾਂ ਮਾਮਲਿਆਂ ਵਿੱਚ "ਗਾਹਕ ਗਿਣਤੀ ਉਪਲਬਧ ਨਹੀਂ" ਦਿਖਾਓ - YouTube ਪਲੇਲਿਸਟ ਖਾਲੀ ਹੋਣ 'ਤੇ NPE ਨੂੰ ਠੀਕ ਕਰੋ - SoundCloud ਵਿੱਚ ਕਿਓਸਕ ਲਈ ਤੁਰੰਤ ਫਿਕਸ - ਰਿਫੈਕਟਰ ਅਤੇ ਬੱਗਫਿਕਸ #1623 - ਚੱਕਰੀ ਖੋਜ ਨਤੀਜੇ #1562 ਨੂੰ ਠੀਕ ਕਰੋ - ਸੀਕ ਬਾਰ ਨੂੰ ਸਥਿਰ ਤੌਰ 'ਤੇ ਬਾਹਰ ਨਾ ਕੱਢੋ - ਫਿਕਸ YT ਪ੍ਰੀਮੀਅਮ ਵੀਡੀਓ ਨੂੰ ਸਹੀ ਢੰਗ ਨਾਲ ਬਲੌਕ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਹੈ - ਕਈ ਵਾਰ ਲੋਡ ਨਾ ਹੋਣ ਵਾਲੇ ਵੀਡੀਓ ਨੂੰ ਠੀਕ ਕਰੋ (DASH ਪਾਰਸਿੰਗ ਦੇ ਕਾਰਨ) - ਵੀਡੀਓ ਵਰਣਨ ਵਿੱਚ ਲਿੰਕ ਫਿਕਸ ਕਰੋ - ਜਦੋਂ ਕੋਈ ਬਾਹਰੀ sdcard 'ਤੇ ਡਾਊਨਲੋਡ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦਾ ਹੈ ਤਾਂ ਚੇਤਾਵਨੀ ਦਿਖਾਓ - ਅਪਵਾਦ ਟਰਿੱਗਰ ਰਿਪੋਰਟ ਦਿਖਾਈ ਗਈ ਕੁਝ ਵੀ ਠੀਕ ਨਾ ਕਰੋ - ਐਂਡਰਾਇਡ 8.1 ਲਈ ਬੈਕਗ੍ਰਾਉਂਡ ਪਲੇਅਰ ਵਿੱਚ ਥੰਬਨੇਲ ਨਹੀਂ ਦਿਖਾਇਆ ਗਿਆ [ਇੱਥੇ ਦੇਖੋ](https://github.com/TeamNewPipe/NewPipe/issues/943) - ਪ੍ਰਸਾਰਣ ਪ੍ਰਾਪਤ ਕਰਨ ਵਾਲੇ ਦੀ ਰਜਿਸਟਰੇਸ਼ਨ ਨੂੰ ਠੀਕ ਕਰੋ। #1641 ਬੰਦ ਹੁੰਦਾ ਹੈ।
+# v0.14.1 ਵਿੱਚ ਬਦਲਾਅ
+
+### ਠੀਕ ਕੀਤਾ ਗਿਆ
+- ਵੀਡੀਓ URL ਨੂੰ ਡੀਕ੍ਰਿਪਟ ਕਰਨ ਵਿੱਚ ਅਸਫਲਤਾ ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ #1659
+- ਵਰਣਨ ਲਿੰਕ ਨੂੰ ਸਹੀ ਢੰਗ ਨਾਲ ਐਕਸਟਰੈਕਟ ਨਾ ਕਰਨ ਦੀ ਸਮੱਸਿਆ ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ #1657
+
+# v0.14.0 ਵਿੱਚ ਬਦਲਾਅ
+
+### ਨਵਾਂ
+- ਨਵਾਂ ਦਰਾਜ਼ ਡਿਜ਼ਾਈਨ #1461
+- ਨਵਾਂ ਅਨੁਕੂਲਿਤ ਫਰੰਟ ਪੇਜ #1461
+
+### ਸੁਧਾਰ
+- ਪੌਪਅੱਪ ਪਲੇਅਰ ਨੂੰ ਬੰਦ ਕਰਨ ਦਾ ਨਵਾਂ ਤਰੀਕਾ #1597
+
+### ਠੀਕ ਕੀਤਾ ਗਿਆ
+- YouTube ਪਲੇਲਿਸਟਾਂ ਖਾਲੀ ਹੋਣ 'ਤੇ NPE ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ
+- SoundCloud ਵਿੱਚ ਕਿਓਸਕ ਲਈ ਤੁਰੰਤ ਠੀਕ ਕੀਤਾ ਗਿਆ
+- ਰੀਫੈਕਟਰ ਅਤੇ ਬੱਗਫਿਕਸ #1623.
diff --git a/fastlane/metadata/android/pa/changelogs/69.txt b/fastlane/metadata/android/pa/changelogs/69.txt
index b6358991b..8956afb54 100644
--- a/fastlane/metadata/android/pa/changelogs/69.txt
+++ b/fastlane/metadata/android/pa/changelogs/69.txt
@@ -1 +1,15 @@
-### ਨਵਾਂ - ਮਿਟਾਓ ਅਤੇ ਸਬਸਕ੍ਰਿਪਸ਼ਨ #1516 ਵਿੱਚ ਸਾਂਝਾ ਕਰੋ - ਟੈਬਲੇਟ UI ਅਤੇ ਗਰਿੱਡ ਸੂਚੀ ਖਾਕਾ #1617 ### ਸੁਧਾਰ - ਆਖਰੀ ਵਰਤੇ ਗਏ ਆਸਪੈਕਟ ਰੇਸ਼ੋ #1748 ਨੂੰ ਸਟੋਰ ਅਤੇ ਰੀਲੋਡ ਕਰੋ - ਪੂਰੇ ਵੀਡੀਓ ਨਾਮ #1771 ਦੇ ਨਾਲ ਡਾਊਨਲੋਡ ਗਤੀਵਿਧੀ ਵਿੱਚ ਲੀਨੀਅਰ ਲੇਆਉਟ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ - ਸਬਸਕ੍ਰਿਪਸ਼ਨ ਟੈਬ #1516 ਦੇ ਅੰਦਰੋਂ ਸਿੱਧਾ ਗਾਹਕੀਆਂ ਨੂੰ ਮਿਟਾਓ ਅਤੇ ਸਾਂਝਾ ਕਰੋ - ਜੇਕਰ ਪਲੇ ਕਤਾਰ ਪਹਿਲਾਂ ਹੀ #1783 ਖਤਮ ਹੋ ਗਈ ਹੈ ਤਾਂ ਹੁਣ ਏਨਕਿਊ ਕਰਨਾ ਵੀਡੀਓ ਚਲਾਉਣ ਨੂੰ ਚਾਲੂ ਕਰਦਾ ਹੈ - ਵਾਲੀਅਮ ਅਤੇ ਚਮਕ ਸੰਕੇਤ #1644 ਲਈ ਵੱਖਰੀ ਸੈਟਿੰਗ - ਸਥਾਨਕਕਰਨ #1792 ਲਈ ਸਮਰਥਨ ਸ਼ਾਮਲ ਕਰੋ ### ਫਿਕਸ - ਲਈ ਪਾਰਸਿੰਗ ਸਮਾਂ ਫਿਕਸ ਕਰੋ। ਫਾਰਮੈਟ, ਇਸ ਲਈ ਨਿਊ ਪਾਈਪ ਨੂੰ ਫਿਨਲੈਂਡ ਵਿੱਚ ਵਰਤਿਆ ਜਾ ਸਕਦਾ ਹੈ - ਗਾਹਕੀ ਦੀ ਗਿਣਤੀ ਨੂੰ ਠੀਕ ਕਰੋ - API 28+ ਡਿਵਾਈਸਾਂ #1830 ਲਈ ਫੋਰਗਰਾਉਂਡ ਸੇਵਾ ਅਨੁਮਤੀ ਸ਼ਾਮਲ ਕਰੋ ### ਜਾਣੇ-ਪਛਾਣੇ ਬੱਗ - ਐਂਡ੍ਰਾਇਡ ਪੀ 'ਤੇ ਪਲੇਬੈਕ ਸਟੇਟ ਨੂੰ ਸੇਵ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ
+### ਨਵਾਂ
+- ਗਾਹਕੀਆਂ 'ਤੇ ਲੰਬੇ ਸਮੇਂ ਤੱਕ ਟੈਪ ਕਰਕੇ ਮਿਟਾਓ ਅਤੇ ਸਾਂਝਾ ਕਰੋ #1516
+- ਟੈਬਲੇਟ UI ਅਤੇ ਗਰਿੱਡ ਸੂਚੀ ਲੇਆਉਟ #1617
+
+### ਸੁਧਾਰ
+- ਵਾਲੀਅਮ ਅਤੇ ਚਮਕ ਸੰਕੇਤਾਂ ਲਈ ਵੱਖਰੀਆਂ ਸੈਟਿੰਗਾਂ #1644
+- ਸਥਾਨਕਕਰਨ ਲਈ ਸਮਰਥਨ ਸ਼ਾਮਲ ਕਰੋ #1792
+
+### ਸੁਧਾਰ
+- . ਫਾਰਮੈਟ ਲਈ ਸਮਾਂ ਪਾਰਸਿੰਗ ਠੀਕ ਕਰੋ ਤਾਂ ਜੋ ਫਿਨਲੈਂਡ ਵਿੱਚ ਨਿਊਪਾਈਪ ਦੀ ਵਰਤੋਂ ਕੀਤੀ ਜਾ ਸਕੇ
+- ਗਾਹਕੀ ਗਿਣਤੀ ਠੀਕ ਕਰੋ
+- API 28+ ਡਿਵਾਈਸਾਂ ਲਈ ਫੋਰਗਰਾਉਂਡ ਸੇਵਾ ਅਨੁਮਤੀ ਸ਼ਾਮਲ ਕਰੋ #1830
+
+### ਜਾਣੇ-ਪਛਾਣੇ ਬੱਗ
+- ਪਲੇਬੈਕ ਸਥਿਤੀ ਨੂੰ ਐਂਡਰਾਇਡ ਪੀ 'ਤੇ ਸੁਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ
diff --git a/fastlane/metadata/android/pa/changelogs/70.txt b/fastlane/metadata/android/pa/changelogs/70.txt
index 97d781d4a..bedc91496 100644
--- a/fastlane/metadata/android/pa/changelogs/70.txt
+++ b/fastlane/metadata/android/pa/changelogs/70.txt
@@ -1 +1,10 @@
-ਧਿਆਨ ਦਿਓ: ਇਹ ਸੰਸਕਰਣ ਸ਼ਾਇਦ ਇੱਕ ਬੱਗਫੈਸਟ ਹੈ, ਬਿਲਕੁਲ ਪਿਛਲੇ ਇੱਕ ਵਾਂਗ। ਹਾਲਾਂਕਿ 17 ਤੋਂ ਪੂਰੀ ਤਰ੍ਹਾਂ ਬੰਦ ਹੋਣ ਦੇ ਕਾਰਨ. ਇੱਕ ਟੁੱਟਿਆ ਹੋਇਆ ਸੰਸਕਰਣ ਕੋਈ ਸੰਸਕਰਣ ਨਾਲੋਂ ਬਿਹਤਰ ਹੈ. ਸਹੀ? ¯\_(ツ)_/¯ ### ਸੁਧਾਰ * ਡਾਊਨਲੋਡ ਕੀਤੀਆਂ ਫਾਈਲਾਂ ਨੂੰ ਹੁਣ ਇੱਕ ਕਲਿੱਕ ਨਾਲ ਖੋਲ੍ਹਿਆ ਜਾ ਸਕਦਾ ਹੈ #1879 * ਐਂਡਰਾਇਡ 4.1 - 4.3 #1884 ਲਈ ਸਹਾਇਤਾ ਛੱਡੋ * ਪੁਰਾਣੇ ਪਲੇਅਰ #1884 ਨੂੰ ਹਟਾਓ * ਮੌਜੂਦਾ ਪਲੇ ਕਤਾਰ ਤੋਂ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਸੱਜੇ #1915 'ਤੇ ਸਵਾਈਪ ਕਰਕੇ ਹਟਾਓ * ਆਟੋ ਕਤਾਰਬੱਧ ਸਟ੍ਰੀਮ ਨੂੰ ਹਟਾਓ ਜਦੋਂ ਇੱਕ ਨਵੀਂ ਸਟ੍ਰੀਮ ਹੱਥੀਂ ਕਤਾਰਬੱਧ ਹੁੰਦੀ ਹੈ #1878 * @kapodamy ਦੁਆਰਾ ਡਾਉਨਲੋਡ ਕਰਨ ਅਤੇ ਗੁੰਮ ਹੋਈਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ #1759 ਨੂੰ ਲਾਗੂ ਕਰਨ ਲਈ ਪੋਸਟ ਪ੍ਰੋਸੈਸਿੰਗ * ਪੋਸਟ-ਪ੍ਰੋਸੈਸਿੰਗ ਬੁਨਿਆਦੀ ਢਾਂਚਾ * "ਬੁਨਿਆਦੀ ਢਾਂਚੇ" ਨੂੰ ਸੰਭਾਲਣ ਲਈ ਸਹੀ ਤਰੁੱਟੀ (ਡਾਊਨਲੋਡਰ ਲਈ) * ਮਲਟੀਪਲ ਡਾਉਨਲੋਡਸ ਦੀ ਬਜਾਏ ਕਤਾਰ * ਲੜੀਬੱਧ ਲੰਬਿਤ ਡਾਉਨਲੋਡਸ (`ਗੀਗਾ` ਫਾਈਲਾਂ) ਨੂੰ ਐਪ ਡੇਟਾ ਵਿੱਚ ਮੂਵ ਕਰੋ * ਅਧਿਕਤਮ ਡਾਊਨਲੋਡ ਦੀ ਮੁੜ ਕੋਸ਼ਿਸ਼ ਨੂੰ ਲਾਗੂ ਕਰੋ * ਉਚਿਤ ਮਲਟੀ-ਥ੍ਰੈਡ ਡਾਊਨਲੋਡ ਵਿਰਾਮ * ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ 'ਤੇ ਜਾਣ ਵੇਲੇ ਡਾਊਨਲੋਡ ਬੰਦ ਕਰੋ (ਕਦੇ ਕੰਮ ਨਹੀਂ ਕਰਦਾ, ਦੂਜਾ ਪੁਆਇੰਟ ਦੇਖੋ) * ਅਗਲੇ ਡਾਉਨਲੋਡਸ ਲਈ ਥਰਿੱਡ ਗਿਣਤੀ ਨੂੰ ਸੁਰੱਖਿਅਤ ਕਰੋ * ਬਹੁਤ ਸਾਰੀਆਂ ਅਸੰਗਤੀਆਂ ਹੱਲ ਕੀਤੀਆਂ ਗਈਆਂ ### ਸਥਿਰ * ਪੂਰਵ-ਨਿਰਧਾਰਤ ਰੈਜ਼ੋਲਿਊਸ਼ਨ ਨਾਲ ਕਰੈਸ਼ ਨੂੰ ਬਿਹਤਰ ਅਤੇ ਸੀਮਤ ਮੋਬਾਈਲ ਡਾਟਾ ਰੈਜ਼ੋਲਿਊਸ਼ਨ #1835 'ਤੇ ਸੈੱਟ ਕਰੋ * ਪੌਪ-ਅੱਪ ਪਲੇਅਰ ਕਰੈਸ਼ ਫਿਕਸਡ #1874 * ਬੈਕਗਰਾਊਂਡ ਪਲੇਅਰ #1901 ਨੂੰ ਖੋਲ੍ਹਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ NPE * ਜਦੋਂ ਆਟੋ ਕਤਾਰ ਯੋਗ ਹੁੰਦੀ ਹੈ ਤਾਂ ਨਵੀਆਂ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਸੰਮਿਲਿਤ ਕਰਨ ਲਈ ਠੀਕ ਕਰੋ #1878 * ਡੀਸਾਈਪਰਿੰਗ ਸ਼ੱਟਟਾਊਨ ਮੁੱਦੇ ਨੂੰ ਹੱਲ ਕੀਤਾ ਗਿਆ
+ਸੁਧਾਰ
+* ਡਾਊਨਲੋਡ ਕੀਤੀਆਂ ਫਾਈਲਾਂ ਹੁਣ ਇੱਕ ਕਲਿੱਕ ਨਾਲ ਖੋਲ੍ਹੀਆਂ ਜਾ ਸਕਦੀਆਂ ਹਨ #1879
+* ਐਂਡਰਾਇਡ 4.1 - 4.3 ਲਈ ਡ੍ਰੌਪ ਸਪੋਰਟ #1884
+* ਪੁਰਾਣੇ ਪਲੇਅਰ ਨੂੰ ਹਟਾਓ #1884
+* ਮੌਜੂਦਾ ਪਲੇ ਕਤਾਰ ਤੋਂ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਸੱਜੇ ਪਾਸੇ ਸਵਾਈਪ ਕਰਕੇ ਹਟਾਓ #1915
+* ਜਦੋਂ ਇੱਕ ਨਵੀਂ ਸਟ੍ਰੀਮ ਨੂੰ ਹੱਥੀਂ ਕਤਾਰਬੱਧ ਕੀਤਾ ਜਾਂਦਾ ਹੈ ਤਾਂ ਆਟੋ ਕਤਾਰਬੱਧ ਸਟ੍ਰੀਮ ਨੂੰ ਹਟਾਓ #1878
+* ਬਹੁਤ ਸਾਰੀਆਂ ਡਾਊਨਲੋਡ ਅਸੰਗਤੀਆਂ ਠੀਕ ਕੀਤੀਆਂ ਗਈਆਂ
+
+ਫਿਕਸਡ
+* ਬਹੁਤ ਸਾਰੀਆਂ ਅਸੰਗਤੀਆਂ ਠੀਕ ਕੀਤੀਆਂ ਗਈਆਂ
diff --git a/fastlane/metadata/android/pa/changelogs/71.txt b/fastlane/metadata/android/pa/changelogs/71.txt
index bafa26f8c..2f11dea82 100644
--- a/fastlane/metadata/android/pa/changelogs/71.txt
+++ b/fastlane/metadata/android/pa/changelogs/71.txt
@@ -1 +1,8 @@
-### ਸੁਧਾਰ * GitHub ਬਿਲਡ ਲਈ ਐਪ ਅਪਡੇਟ ਨੋਟੀਫਿਕੇਸ਼ਨ ਸ਼ਾਮਲ ਕਰੋ (@krtkush ਦੁਆਰਾ #1608) * ਡਾਊਨਲੋਡਰ ਵਿੱਚ ਕਈ ਸੁਧਾਰ (@kapodamy ਦੁਆਰਾ #1944): * ਗੁੰਮ ਹੋਏ ਚਿੱਟੇ ਆਈਕਨ ਸ਼ਾਮਲ ਕਰੋ ਅਤੇ ਆਈਕਨ ਦੇ ਰੰਗਾਂ ਨੂੰ ਬਦਲਣ ਲਈ ਹਾਰਡਕੋਰਡ ਤਰੀਕੇ ਦੀ ਵਰਤੋਂ ਕਰੋ * ਜਾਂਚ ਕਰੋ ਕਿ ਕੀ ਇਟਰੇਟਰ ਸ਼ੁਰੂ ਕੀਤਾ ਗਿਆ ਹੈ (ਫਿਕਸ #2031) * ਨਵੇਂ ਮੁਕਸਰ ਵਿੱਚ "ਪੋਸਟ-ਪ੍ਰੋਸੈਸਿੰਗ ਫੇਲ੍ਹ" ਗਲਤੀ ਦੇ ਨਾਲ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ * ਨਵਾਂ MPEG-4 ਮੁਕਸਰ ਫਿਕਸਿੰਗ ਗੈਰ-ਸਿੰਕਰੋਨਸ ਵੀਡੀਓ ਅਤੇ ਆਡੀਓ ਸਟ੍ਰੀਮਜ਼ (#2039) ### ਸਥਿਰ * YouTube ਲਾਈਵ ਸਟ੍ਰੀਮਾਂ ਥੋੜ੍ਹੇ ਸਮੇਂ ਬਾਅਦ ਚੱਲਣੀਆਂ ਬੰਦ ਹੋ ਜਾਂਦੀਆਂ ਹਨ (@yausername ਦੁਆਰਾ #1996)
+ਸੁਧਾਰ
+* GitHub ਬਿਲਡ ਲਈ ਐਪ ਅੱਪਡੇਟ ਸੂਚਨਾ ਸ਼ਾਮਲ ਕਰੋ (#1608 @krtkush ਦੁਆਰਾ)
+* ਡਾਊਨਲੋਡਰ ਵਿੱਚ ਕਈ ਸੁਧਾਰ (#1944 @kapodamy ਦੁਆਰਾ)
+* ਨਵੇਂ ਮਕਸਰ ਵਿੱਚ "ਪੋਸਟ-ਪ੍ਰੋਸੈਸਿੰਗ ਅਸਫਲ" ਗਲਤੀ ਨਾਲ ਡਾਊਨਲੋਡਾਂ ਨੂੰ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ
+* ਨਵਾਂ MPEG-4 ਮਕਸਰ ਗੈਰ-ਸਮਕਾਲੀ ਵੀਡੀਓ ਅਤੇ ਆਡੀਓ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਠੀਕ ਕਰਦਾ ਹੈ (#2039)
+
+ਫਿਕਸਡ
+* YouTube ਲਾਈਵ ਸਟ੍ਰੀਮਾਂ ਥੋੜ੍ਹੇ ਸਮੇਂ ਬਾਅਦ ਚੱਲਣਾ ਬੰਦ ਕਰ ਦਿੰਦੀਆਂ ਹਨ (#1996 @yausername ਦੁਆਰਾ)
diff --git a/fastlane/metadata/android/pa/changelogs/740.txt b/fastlane/metadata/android/pa/changelogs/740.txt
index 6a2dbdc86..62da0f9c3 100644
--- a/fastlane/metadata/android/pa/changelogs/740.txt
+++ b/fastlane/metadata/android/pa/changelogs/740.txt
@@ -1 +1,8 @@
-ਬਦਲਾਅ ਸੂਚੀ ਅਨੁਵਾਦ ਕਰਣਯੋਗ ਨਹੀਂ। ਬਿਲਕੁਲ ਬਕਵਾਸ
+ਸੁਧਾਰ
+
+- ਟਿੱਪਣੀਆਂ ਵਿੱਚ ਲਿੰਕਾਂ ਨੂੰ ਕਲਿੱਕ ਕਰਨ ਯੋਗ ਬਣਾਓ, ਟੈਕਸਟ ਦਾ ਆਕਾਰ ਵਧਾਓ
+- ਟਿੱਪਣੀਆਂ ਵਿੱਚ ਟਾਈਮਸਟੈਂਪ ਕੀਤੇ ਲਿੰਕਾਂ 'ਤੇ ਕਲਿੱਕ ਕੀਤੇ ਜਾਣ 'ਤੇ ਖੋਜ ਕਰੋ
+- ਜਦੋਂ ਸਾਂਝਾ ਕੀਤਾ ਟੈਕਸਟ URL ਨਾ ਹੋਵੇ ਤਾਂ ਖੋਜ ਕਰੋ
+- ਮੁੱਖ ਵੀਡੀਓ ਪਲੇਅਰ ਵਿੱਚ "ਹੁਣੇ ਸਾਂਝਾ ਕਰੋ" ਬਟਨ ਸ਼ਾਮਲ ਕਰੋ
+- ExoPlayer ਨੂੰ 2.9.6 'ਤੇ ਅੱਪਡੇਟ ਕਰਨਾ
+
diff --git a/fastlane/metadata/android/pa/changelogs/750.txt b/fastlane/metadata/android/pa/changelogs/750.txt
index 0b875b705..c24183ddb 100644
--- a/fastlane/metadata/android/pa/changelogs/750.txt
+++ b/fastlane/metadata/android/pa/changelogs/750.txt
@@ -1 +1,9 @@
-ਨਵਾਂ ਪਲੇਬੈਕ ਰੈਜ਼ਿਊਮੇ #2288 • ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਮੁੜ ਸ਼ੁਰੂ ਕਰੋ ਜਿੱਥੇ ਤੁਸੀਂ ਪਿਛਲੀ ਵਾਰ ਰੁਕੇ ਸੀ ਡਾਊਨਲੋਡਰ ਸੁਧਾਰ #2149 • ਬਾਹਰੀ SD-ਕਾਰਡਾਂ 'ਤੇ ਡਾਊਨਲੋਡ ਸਟੋਰ ਕਰਨ ਲਈ ਸਟੋਰੇਜ਼ ਐਕਸੈਸ ਫਰੇਮਵਰਕ ਦੀ ਵਰਤੋਂ ਕਰੋ • ਨਵਾਂ mp4 muxer • ਡਾਊਨਲੋਡ ਸ਼ੁਰੂ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਵਿਕਲਪਿਕ ਤੌਰ 'ਤੇ ਡਾਉਨਲੋਡ ਡਾਇਰੈਕਟਰੀ ਨੂੰ ਬਦਲੋ • ਮੀਟਰਡ ਨੈੱਟਵਰਕਾਂ ਦਾ ਆਦਰ ਕਰੋ ਸੁਧਾਰ • gema ਸਤਰ #2295 ਨੂੰ ਹਟਾਇਆ • ਗਤੀਵਿਧੀ ਜੀਵਨ ਚੱਕਰ #2444 ਦੌਰਾਨ ਹੈਂਡਲ (ਆਟੋ) ਰੋਟੇਸ਼ਨ ਤਬਦੀਲੀਆਂ • ਲੰਬੇ-ਦਬਾਓ ਮੀਨੂ ਨੂੰ ਇਕਸਾਰ #2368 ਬਣਾਓ ਸਥਿਰ • ਫਿਕਸਡ ਚੁਣਿਆ ਹੋਇਆ ਉਪਸਿਰਲੇਖ ਟਰੈਕ ਨਾਮ #2394 ਨਹੀਂ ਦਿਖਾਇਆ ਜਾ ਰਿਹਾ ਹੈ • ਐਪ ਅੱਪਡੇਟ ਦੀ ਜਾਂਚ ਅਸਫਲ ਹੋਣ 'ਤੇ ਕ੍ਰੈਸ਼ ਨਾ ਹੋਵੋ (GitHub ਸੰਸਕਰਣ) #2423 • ਸਥਿਰ ਡਾਊਨਲੋਡ 99.9% #2440 'ਤੇ ਅਟਕ ਗਏ • ਪਲੇ ਕਤਾਰ ਮੈਟਾਡੇਟਾ #2453 ਨੂੰ ਅੱਪਡੇਟ ਕਰੋ • [SoundCloud] ਪਲੇਲਿਸਟਸ ਲੋਡ ਕਰਨ ਵੇਲੇ ਸਥਿਰ ਕਰੈਸ਼ TeamNewPipe/NewPipeExtractor#170 • [YouTube] ਸਥਿਰ ਅਵਧੀ ਨੂੰ ਪਾਰਸਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ TeamNewPipe/NewPipeExtractor#177
+ਨਵਾਂ
+ਪਲੇਬੈਕ ਰੈਜ਼ਿਊਮੇ #2288
+ਡਾਊਨਲੋਡਰ ਸੁਧਾਰ #2149
+• ਬਾਹਰੀ SD-ਕਾਰਡਾਂ 'ਤੇ ਡਾਊਨਲੋਡ ਸਟੋਰ ਕਰਨ ਲਈ ਸਟੋਰੇਜ ਐਕਸੈਸ ਫਰੇਮਵਰਕ ਦੀ ਵਰਤੋਂ ਕਰੋ
+• ਡਾਊਨਲੋਡ ਸ਼ੁਰੂ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਵਿਕਲਪਿਕ ਤੌਰ 'ਤੇ ਡਾਊਨਲੋਡ ਡਾਇਰੈਕਟਰੀ ਬਦਲੋ
+• ਮੀਟਰ ਕੀਤੇ ਨੈੱਟਵਰਕਾਂ ਦਾ ਸਤਿਕਾਰ ਕਰੋ
+
+ਸਥਿਰ
+• [YouTube] ਸਥਿਰ ਮਿਆਦ ਨੂੰ ਪਾਰਸ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ TeamNewPipe/NewPipeExtractor#177
diff --git a/fastlane/metadata/android/pa/changelogs/760.txt b/fastlane/metadata/android/pa/changelogs/760.txt
index fd4b8f2a4..6279139d0 100644
--- a/fastlane/metadata/android/pa/changelogs/760.txt
+++ b/fastlane/metadata/android/pa/changelogs/760.txt
@@ -1 +1,10 @@
-0.17.1 ਵਿੱਚ ਬਦਲਾਅ ਨਵਾਂ • ਥਾਈ ਸਥਾਨਕਕਰਨ ਸੁਧਾਰ • ਦੁਬਾਰਾ #2518 ਪਲੇਲਿਸਟਾਂ ਲਈ ਲੰਬੇ-ਦਬਾਓ ਮੀਨੂ ਵਿੱਚ ਇੱਥੇ ਪਲੇ ਸ਼ੁਰੂ ਕਰੋ ਐਕਸ਼ਨ ਸ਼ਾਮਲ ਕਰੋ • SAF / ਪੁਰਾਤਨ ਫਾਈਲ ਪਿਕਰ #2521 ਲਈ ਸਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ ਸਥਿਰ • ਐਪਸ #2487 ਨੂੰ ਬਦਲਦੇ ਸਮੇਂ ਡਾਊਨਲੋਡ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਗਾਇਬ ਹੋਣ ਵਾਲੇ ਬਟਨਾਂ ਨੂੰ ਠੀਕ ਕਰੋ • ਫਿਕਸ ਪਲੇਬੈਕ ਸਥਿਤੀ ਸਟੋਰ ਕੀਤੀ ਜਾਂਦੀ ਹੈ ਹਾਲਾਂਕਿ ਦੇਖਣ ਦਾ ਇਤਿਹਾਸ ਅਯੋਗ ਹੈ • ਸੂਚੀ ਦ੍ਰਿਸ਼ #2517 ਵਿੱਚ ਪਲੇਬੈਕ ਸਥਿਤੀ ਦੇ ਕਾਰਨ ਘਟੇ ਪ੍ਰਦਰਸ਼ਨ ਨੂੰ ਠੀਕ ਕਰੋ • [ਐਕਸਟ੍ਰੈਕਟਰ] ReCaptchaActivity #2527, TeamNewPipe/NewPipeExtractor#186 ਫਿਕਸ • [ਐਕਸਟ੍ਰੈਕਟਰ] [YouTube] ਜਦੋਂ ਪਲੇਲਿਸਟਾਂ ਨਤੀਜੇ ਵਿੱਚ ਹੋਣ ਤਾਂ ਆਮ ਖੋਜ ਗਲਤੀ ਨੂੰ ਠੀਕ ਕਰੋ TeamNewPipe/NewPipeExtractor#185 0.17.0 ਵਿੱਚ ਬਦਲਾਅ ਨਵਾਂ ਪਲੇਬੈਕ ਰੈਜ਼ਿਊਮੇ #2288 • ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਮੁੜ ਸ਼ੁਰੂ ਕਰੋ ਜਿੱਥੇ ਤੁਸੀਂ ਪਿਛਲੀ ਵਾਰ ਰੁਕੇ ਸੀ ਡਾਊਨਲੋਡਰ ਸੁਧਾਰ #2149 • ਬਾਹਰੀ SD-ਕਾਰਡਾਂ 'ਤੇ ਡਾਊਨਲੋਡ ਸਟੋਰ ਕਰਨ ਲਈ ਸਟੋਰੇਜ਼ ਐਕਸੈਸ ਫਰੇਮਵਰਕ ਦੀ ਵਰਤੋਂ ਕਰੋ • ਨਵਾਂ mp4 muxer • ਡਾਊਨਲੋਡ ਸ਼ੁਰੂ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਵਿਕਲਪਿਕ ਤੌਰ 'ਤੇ ਡਾਉਨਲੋਡ ਡਾਇਰੈਕਟਰੀ ਨੂੰ ਬਦਲੋ • ਮੀਟਰਡ ਨੈੱਟਵਰਕਾਂ ਦਾ ਆਦਰ ਕਰੋ ਸੁਧਾਰ • gema ਸਤਰ #2295 ਨੂੰ ਹਟਾਇਆ • ਗਤੀਵਿਧੀ ਜੀਵਨ ਚੱਕਰ #2444 ਦੌਰਾਨ ਹੈਂਡਲ (ਆਟੋ) ਰੋਟੇਸ਼ਨ ਤਬਦੀਲੀਆਂ • ਲੰਬੇ-ਦਬਾਓ ਮੀਨੂ ਨੂੰ ਇਕਸਾਰ #2368 ਬਣਾਓ ਸਥਿਰ • ਫਿਕਸਡ ਚੁਣਿਆ ਹੋਇਆ ਉਪਸਿਰਲੇਖ ਟਰੈਕ ਨਾਮ #2394 ਨਹੀਂ ਦਿਖਾਇਆ ਜਾ ਰਿਹਾ ਹੈ • ਐਪ ਅੱਪਡੇਟ ਦੀ ਜਾਂਚ ਅਸਫਲ ਹੋਣ 'ਤੇ ਕ੍ਰੈਸ਼ ਨਾ ਹੋਵੋ (GitHub ਸੰਸਕਰਣ) #2423 • ਸਥਿਰ ਡਾਊਨਲੋਡ 99.9% #2440 'ਤੇ ਅਟਕ ਗਏ • ਪਲੇ ਕਤਾਰ ਮੈਟਾਡੇਟਾ #2453 ਨੂੰ ਅੱਪਡੇਟ ਕਰੋ • [SoundCloud] ਪਲੇਲਿਸਟਸ ਲੋਡ ਕਰਨ ਵੇਲੇ ਸਥਿਰ ਕਰੈਸ਼ TeamNewPipe/NewPipeExtractor#170 • [YouTube] ਸਥਿਰ ਅਵਧੀ ਨੂੰ ਪਾਰਸਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ TeamNewPipe/NewPipeExtractor#177
+0.17.1 ਵਿੱਚ ਬਦਲਾਅ
+
+ਸੁਧਾਰਿਆ ਗਿਆ
+• ਪਲੇਲਿਸਟਾਂ ਲਈ ਦੁਬਾਰਾ ਲੰਬੇ-ਦਬਾਓ ਵਾਲੇ ਮੀਨੂ ਵਿੱਚ ਇੱਥੇ ਚਲਾਉਣਾ ਸ਼ੁਰੂ ਕਰੋ ਐਕਸ਼ਨ ਸ਼ਾਮਲ ਕਰੋ
+• SAF / ਲੀਗੇਸੀ ਫਾਈਲ ਪਿਕਰ #2521 ਲਈ ਸਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ
+ਫਿਕਸਡ
+• ਐਪਸ ਨੂੰ ਸਵਿੱਚ ਕਰਦੇ ਸਮੇਂ ਡਾਊਨਲੋਡ ਵਿਊ ਵਿੱਚ ਗਾਇਬ ਹੋਣ ਵਾਲੇ ਬਟਨਾਂ ਨੂੰ ਠੀਕ ਕਰੋ #2487
+• ਦੇਖਣ ਦੇ ਇਤਿਹਾਸ ਨੂੰ ਅਯੋਗ ਹੋਣ ਦੇ ਬਾਵਜੂਦ ਸਟੋਰ ਕੀਤੀ ਗਈ ਪਲੇਬੈਕ ਸਥਿਤੀ ਨੂੰ ਠੀਕ ਕਰੋ
+• ਸੂਚੀ ਵਿਊ ਵਿੱਚ ਪਲੇਬੈਕ ਸਥਿਤੀ ਕਾਰਨ ਘਟੀ ਹੋਈ ਪ੍ਰਦਰਸ਼ਨ ਨੂੰ ਠੀਕ ਕਰੋ
+• [ਐਕਸਟ੍ਰੈਕਟਰ] [YouTube] ਜਦੋਂ ਪਲੇਲਿਸਟਾਂ ਨਤੀਜਿਆਂ ਵਿੱਚ ਹੋਣ ਤਾਂ ਆਮ ਖੋਜ ਗਲਤੀ ਨੂੰ ਠੀਕ ਕਰੋ
diff --git a/fastlane/metadata/android/pa/changelogs/780.txt b/fastlane/metadata/android/pa/changelogs/780.txt
index 999a24468..923a0410a 100644
--- a/fastlane/metadata/android/pa/changelogs/780.txt
+++ b/fastlane/metadata/android/pa/changelogs/780.txt
@@ -1 +1,11 @@
-0.17.3 ਵਿੱਚ ਬਦਲਾਅ ਸੁਧਾਰ • ਪਲੇਬੈਕ ਸਥਿਤੀਆਂ #2550 ਨੂੰ ਸਾਫ਼ ਕਰਨ ਲਈ ਵਿਕਲਪ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ • ਫਾਈਲ ਪਿਕਰ #2591 ਵਿੱਚ ਲੁਕੀਆਂ ਹੋਈਆਂ ਡਾਇਰੈਕਟਰੀਆਂ ਦਿਖਾਓ • NewPipe #2488 ਨਾਲ ਖੋਲ੍ਹੇ ਜਾਣ ਵਾਲੇ `invidio.us` ਉਦਾਹਰਨਾਂ ਤੋਂ ਸਮਰਥਨ URL • `music.youtube.com` URLs TeamNewPipe/NewPipeExtractor#194 ਲਈ ਸਮਰਥਨ ਸ਼ਾਮਲ ਕਰੋ ਸਥਿਰ • [YouTube] ਸਥਿਰ 'java.lang.IllegalArgumentException #192 • [YouTube] ਸਥਿਰ ਲਾਈਵ ਸਟ੍ਰੀਮਾਂ ਕੰਮ ਨਹੀਂ ਕਰ ਰਹੀਆਂ TeamNewPipe/NewPipeExtractor#195 • ਇੱਕ ਸਟ੍ਰੀਮ #2592 ਨੂੰ ਡਾਊਨਲੋਡ ਕਰਨ ਵੇਲੇ ਐਂਡਰੌਇਡ ਪਾਈ ਵਿੱਚ ਸਥਿਰ ਪ੍ਰਦਰਸ਼ਨ ਸਮੱਸਿਆ
+0.17.3 ਵਿੱਚ ਬਦਲਾਅ
+
+ਸੁਧਾਰਿਆ ਗਿਆ
+• ਪਲੇਬੈਕ ਸਥਿਤੀਆਂ ਨੂੰ ਸਾਫ਼ ਕਰਨ ਲਈ ਵਿਕਲਪ ਜੋੜਿਆ ਗਿਆ #2550
+• ਫਾਈਲ ਚੋਣਕਾਰ #2591 ਵਿੱਚ ਲੁਕੀਆਂ ਹੋਈਆਂ ਡਾਇਰੈਕਟਰੀਆਂ ਦਿਖਾਓ
+• NewPipe #2488 ਨਾਲ ਖੋਲ੍ਹੇ ਜਾਣ ਵਾਲੇ `invidio.us` ਉਦਾਹਰਣਾਂ ਤੋਂ URL ਦਾ ਸਮਰਥਨ ਕਰੋ
+• `music.youtube.com` URL ਲਈ ਸਮਰਥਨ ਸ਼ਾਮਲ ਕਰੋ
+
+ਸਥਿਰ
+• [YouTube] ਫਿਕਸਡ ਲਾਈਵ ਸਟ੍ਰੀਮਾਂ ਕੰਮ ਨਹੀਂ ਕਰ ਰਹੀਆਂ
+• ਸਟ੍ਰੀਮ ਡਾਊਨਲੋਡ ਕਰਦੇ ਸਮੇਂ ਐਂਡਰਾਇਡ ਪਾਈ ਵਿੱਚ ਪ੍ਰਦਰਸ਼ਨ ਸਮੱਸਿਆ ਹੱਲ ਕੀਤੀ ਗਈ #2592
diff --git a/fastlane/metadata/android/pa/changelogs/790.txt b/fastlane/metadata/android/pa/changelogs/790.txt
index f841801eb..28627c7ec 100644
--- a/fastlane/metadata/android/pa/changelogs/790.txt
+++ b/fastlane/metadata/android/pa/changelogs/790.txt
@@ -1 +1,11 @@
-ਸੁਧਾਰ • ਅੰਨ੍ਹੇ ਲੋਕਾਂ #2655 ਲਈ ਪਹੁੰਚਯੋਗਤਾ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ ਹੋਰ ਸਿਰਲੇਖ ਸ਼ਾਮਲ ਕਰੋ • ਡਾਉਨਲੋਡ ਫੋਲਡਰ ਸੈਟਿੰਗ ਦੀ ਭਾਸ਼ਾ ਨੂੰ ਵਧੇਰੇ ਇਕਸਾਰ ਅਤੇ ਘੱਟ ਅਸਪਸ਼ਟ #2637 ਬਣਾਓ ਸਥਿਰ • ਜਾਂਚ ਕਰੋ ਕਿ ਕੀ ਬਲਾਕ ਵਿੱਚ ਆਖਰੀ ਬਾਈਟ #2646 ਡਾਊਨਲੋਡ ਕੀਤੀ ਗਈ ਹੈ • ਵੀਡੀਓ ਡਿਟੇਲ ਫਰੈਗਮੈਂਟ #2672 ਵਿੱਚ ਸਥਿਰ ਸਕ੍ਰੋਲਿੰਗ • ਡਬਲ ਸਰਚ ਕਲੀਅਰ ਬਾਕਸ ਐਨੀਮੇਸ਼ਨ ਨੂੰ ਇੱਕ #2695 ਵਿੱਚ ਹਟਾਓ • [SoundCloud] ਕਲਾਇਟ_ਆਈਡੀ ਐਕਸਟਰੈਕਸ਼ਨ #2745 ਨੂੰ ਠੀਕ ਕਰੋ ਵਿਕਾਸ • NewPipeExtractor ਤੋਂ ਵਿਰਾਸਤ ਵਿੱਚ ਮਿਲੀ ਗੁੰਮ ਨਿਰਭਰਤਾ ਨੂੰ NewPipe #2535 ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ • AndroidX #2685 'ਤੇ ਮਾਈਗ੍ਰੇਟ ਕਰੋ • ExoPlayer 2.10.6 #2697, #2736 ਨੂੰ ਅੱਪਡੇਟ ਕਰੋ
+ਸੁਧਾਰਿਆ ਗਿਆ
+• ਹੋਰ ਸਿਰਲੇਖ ਸ਼ਾਮਲ ਕਰੋ
+
+ਠੀਕ ਕੀਤਾ ਗਿਆ
+• ਜਾਂਚ ਕਰੋ ਕਿ ਕੀ ਬਲਾਕ ਵਿੱਚ ਆਖਰੀ ਬਾਈਟ ਡਾਊਨਲੋਡ ਕੀਤਾ ਗਿਆ ਹੈ #2646
+• ਵੀਡੀਓ ਵੇਰਵੇ ਵਾਲੇ ਟੁਕੜੇ #2672 ਵਿੱਚ ਸਕ੍ਰੌਲਿੰਗ ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ
+• [SoundCloud] client_id ਐਕਸਟਰੈਕਸ਼ਨ #2745 ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ
+
+ਵਿਕਾਸ
+• AndroidX 'ਤੇ ਮਾਈਗ੍ਰੇਟ ਕਰੋ
+• ExoPlayer 2.10.6 'ਤੇ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ
diff --git a/fastlane/metadata/android/pa/changelogs/800.txt b/fastlane/metadata/android/pa/changelogs/800.txt
index 53868c894..08940d095 100644
--- a/fastlane/metadata/android/pa/changelogs/800.txt
+++ b/fastlane/metadata/android/pa/changelogs/800.txt
@@ -1 +1,10 @@
-ਨਵਾਂ • P2P (#2201) [ਬੀਟਾ] ਤੋਂ ਬਿਨਾਂ PeerTube ਸਮਰਥਨ: ◦ PeerTube ਉਦਾਹਰਨਾਂ ਤੋਂ ਵੀਡੀਓ ਦੇਖੋ ਅਤੇ ਡਾਊਨਲੋਡ ਕਰੋ ◦ ਪੂਰੀ PeerTube ਸੰਸਾਰ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਲਈ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਉਦਾਹਰਨਾਂ ਸ਼ਾਮਲ ਕਰੋ ◦ Android 4.4 ਅਤੇ 7.1 'ਤੇ SSL ਹੈਂਡਸ਼ੇਕ ਨਾਲ ਸਮੱਸਿਆਵਾਂ ਹੋ ਸਕਦੀਆਂ ਹਨ ਜਦੋਂ ਕੁਝ ਖਾਸ ਮੌਕਿਆਂ 'ਤੇ ਪਹੁੰਚ ਕਰਦੇ ਸਮੇਂ ਨੈੱਟਵਰਕ ਗੜਬੜ ਹੋ ਜਾਂਦੀ ਹੈ। • ਡਾਊਨਲੋਡਰ (#2679): ◦ ਡਾਊਨਲੋਡ ETA ਦੀ ਗਣਨਾ ਕਰੋ ◦ ਓਪਸ (ਵੈਬ ਫਾਈਲਾਂ) ਨੂੰ ogg ਵਜੋਂ ਡਾਊਨਲੋਡ ਕਰੋ ◦ ਲੰਬੇ ਵਿਰਾਮ ਤੋਂ ਬਾਅਦ ਡਾਊਨਲੋਡ ਮੁੜ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਮਿਆਦ ਪੁੱਗ ਚੁੱਕੇ ਡਾਊਨਲੋਡ ਲਿੰਕਾਂ ਨੂੰ ਮੁੜ-ਹਾਸਲ ਕਰੋ ਸੁਧਾਰ • ਕਿਓਸਕਫ੍ਰੈਗਮੈਂਟ ਨੂੰ ਤਰਜੀਹੀ ਸਮਗਰੀ ਵਾਲੇ ਦੇਸ਼ ਵਿੱਚ ਤਬਦੀਲੀਆਂ ਤੋਂ ਜਾਣੂ ਕਰਵਾਓ ਅਤੇ ਸਾਰੀਆਂ ਮੁੱਖ ਟੈਬਾਂ #2742 ਦੀ ਕਾਰਗੁਜ਼ਾਰੀ ਵਿੱਚ ਸੁਧਾਰ ਕਰੋ। • ਐਕਸਟਰੈਕਟਰ #2713 ਤੋਂ ਨਵੇਂ ਸਥਾਨਕਕਰਨ ਅਤੇ ਡਾਉਨਲੋਡਰ ਲਾਗੂਕਰਨ ਦੀ ਵਰਤੋਂ ਕਰੋ • "ਡਿਫੌਲਟ ਕਿਓਸਕ" ਸਤਰ ਨੂੰ ਅਨੁਵਾਦਯੋਗ ਬਣਾਓ • ਬਲੈਕ ਥੀਮ #2569 ਲਈ ਬਲੈਕ ਨੈਵੀਗੇਸ਼ਨ ਪੱਟੀ ਸਥਿਰ • ਇੱਕ ਬੱਗ ਫਿਕਸ ਕੀਤਾ ਗਿਆ ਹੈ ਜੋ ਪੌਪਅੱਪ ਪਲੇਅਰ ਨੂੰ ਹਿਲਾ ਨਹੀਂ ਸਕਦਾ ਸੀ ਜੇਕਰ ਪੌਪਅੱਪ ਪਲੇਅਰ #2772 ਨੂੰ ਹਿਲਾਉਂਦੇ ਸਮੇਂ ਕੋਈ ਹੋਰ ਉਂਗਲ ਰੱਖੀ ਜਾਂਦੀ ਹੈ • ਪਲੇਲਿਸਟਾਂ ਨੂੰ ਅਪਲੋਡਰ ਦੀ ਗੁੰਮਸ਼ੁਦਗੀ ਦੀ ਆਗਿਆ ਦਿਓ ਅਤੇ ਇਸ ਸਮੱਸਿਆ ਨਾਲ ਸਬੰਧਤ ਕ੍ਰੈਸ਼ਾਂ ਨੂੰ ਠੀਕ ਕਰੋ #2724, TeamNewPipe/NewPipeExtractor#219 • MediaCCC ਅਤੇ ਕੁਝ PeerTube ਉਦਾਹਰਨਾਂ #2792 ਨਾਲ TLS ਹੈਂਡਸ਼ੇਕ ਨੂੰ ਠੀਕ ਕਰਨ ਲਈ Android 4.4 ਡਿਵਾਈਸਾਂ (API 19/KitKat) 'ਤੇ TLS1.1/1.2 ਨੂੰ ਸਮਰੱਥ ਕਰਨਾ • [SoundCloud] ਫਿਕਸਡ ਕਲਾਈਂਟ_ਆਈਡੀ ਐਕਸਟ੍ਰੈਕਸ਼ਨ TeamNewPipe/NewPipeExtractor#217 • [SoundCloud] ਆਡੀਓ ਸਟ੍ਰੀਮ ਕੱਢਣ ਨੂੰ ਠੀਕ ਕਰੋ ਵਿਕਾਸ • ExoPlayer ਨੂੰ 2.10.8 #2791, #2816 'ਤੇ ਅੱਪਡੇਟ ਕਰੋ • Gradle ਨੂੰ 3.5.1 ਵਿੱਚ ਅੱਪਡੇਟ ਕਰੋ ਅਤੇ Kotlin ਸਹਿਯੋਗ #2714 ਸ਼ਾਮਲ ਕਰੋ
+ਨਵਾਂ
+• P2P ਤੋਂ ਬਿਨਾਂ PeerTube ਸਹਾਇਤਾ (#2201) [ਬੀਟਾ]:
+
+◦ ਲੰਬੇ ਵਿਰਾਮ ਤੋਂ ਬਾਅਦ ਡਾਊਨਲੋਡ ਮੁੜ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਮਿਆਦ ਪੁੱਗ ਚੁੱਕੇ ਡਾਊਨਲੋਡ ਲਿੰਕਾਂ ਨੂੰ ਮੁੜ ਪ੍ਰਾਪਤ ਕਰੋ
+
+ਸੁਧਾਰਿਆ ਗਿਆ
+• ਪਸੰਦੀਦਾ ਸਮੱਗਰੀ ਦੇਸ਼ ਵਿੱਚ ਤਬਦੀਲੀਆਂ ਬਾਰੇ KioskFragment ਨੂੰ ਸੂਚਿਤ ਕਰੋ ਅਤੇ ਸਾਰੇ ਮੁੱਖ ਟੈਬਾਂ ਵਿੱਚ ਪ੍ਰਦਰਸ਼ਨ ਵਿੱਚ ਸੁਧਾਰ ਕਰੋ #2742
+
+ਸਥਿਰ
+• Android 4.4 ਡਿਵਾਈਸਾਂ (API 19/KitKat) 'ਤੇ TLS1.1/1.2 ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ
diff --git a/fastlane/metadata/android/pa/changelogs/810.txt b/fastlane/metadata/android/pa/changelogs/810.txt
index 96a2b9da5..d10bc6913 100644
--- a/fastlane/metadata/android/pa/changelogs/810.txt
+++ b/fastlane/metadata/android/pa/changelogs/810.txt
@@ -1 +1,11 @@
-ਨਵਾਂ • ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲਦੇ ਸਮੇਂ ਲੌਕ ਸਕ੍ਰੀਨ 'ਤੇ ਵੀਡੀਓ ਥੰਬਨੇਲ ਦਿਖਾਓ ਸੁਧਾਰ • ਬੈਕਗ੍ਰਾਉਂਡ / ਪੌਪਅੱਪ ਬਟਨ 'ਤੇ ਲੰਬੇ ਸਮੇਂ ਤੱਕ ਦਬਾਉਣ 'ਤੇ ਕਤਾਰ ਵਿੱਚ ਸਥਾਨਕ ਪਲੇਲਿਸਟ ਸ਼ਾਮਲ ਕਰੋ • ਮੁੱਖ ਪੰਨਾ ਟੈਬਾਂ ਨੂੰ ਸਕ੍ਰੋਲ ਕਰਨ ਯੋਗ ਬਣਾਓ ਅਤੇ ਸਿਰਫ਼ ਇੱਕ ਟੈਬ ਹੋਣ 'ਤੇ ਲੁਕਾਓ • ਬੈਕਗ੍ਰਾਉਂਡ ਪਲੇਅਰ ਵਿੱਚ ਸੂਚਨਾ ਥੰਬਨੇਲ ਅੱਪਡੇਟ ਦੀ ਸੀਮਾ ਮਾਤਰਾ • ਖਾਲੀ ਸਥਾਨਕ ਪਲੇਲਿਸਟਾਂ ਲਈ ਡਮੀ ਥੰਬਨੇਲ ਸ਼ਾਮਲ ਕਰੋ • *.webm ਦੀ ਬਜਾਏ *.opus ਫਾਈਲ ਐਕਸਟੈਂਸ਼ਨ ਦੀ ਵਰਤੋਂ ਕਰੋ ਅਤੇ ਡਾਊਨਲੋਡ ਡ੍ਰੌਪਡਾਉਨ ਵਿੱਚ "WebM Opus" ਦੀ ਬਜਾਏ ਫਾਰਮੈਟ ਲੇਬਲ ਵਿੱਚ "opus" ਦਿਖਾਓ • "ਡਾਊਨਲੋਡ" ਵਿੱਚ ਡਾਊਨਲੋਡ ਕੀਤੀਆਂ ਫ਼ਾਈਲਾਂ ਜਾਂ ਡਾਊਨਲੋਡ ਇਤਿਹਾਸ ਨੂੰ ਮਿਟਾਉਣ ਲਈ ਬਟਨ ਸ਼ਾਮਲ ਕਰੋ • [YouTube] /c/shortened_url ਚੈਨਲ ਲਿੰਕਾਂ ਲਈ ਸਮਰਥਨ ਸ਼ਾਮਲ ਕਰੋ ਸਥਿਰ • NewPipe ਨਾਲ ਵੀਡੀਓ ਸਾਂਝਾ ਕਰਨ ਅਤੇ ਇਸ ਦੀਆਂ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਸਿੱਧੇ ਡਾਊਨਲੋਡ ਕਰਨ ਵੇਲੇ ਕਈ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਹੱਲ ਕੀਤਾ ਗਿਆ • ਇਸ ਦੇ ਸਿਰਜਣ ਥ੍ਰੈਡ ਤੋਂ ਬਾਹਰ ਸਥਿਰ ਪਲੇਅਰ ਪਹੁੰਚ • ਸਥਿਰ ਖੋਜ ਨਤੀਜੇ ਪੇਜਿੰਗ • [YouTube] ਨਿਸ਼ਚਤ ਸਵਿਚਿੰਗ ਚਾਲੂ ਕਰਨ ਨਾਲ NPE ਹੁੰਦਾ ਹੈ • [YouTube] ਇੱਕ invidio.us url ਖੋਲ੍ਹਣ ਵੇਲੇ ਟਿੱਪਣੀਆਂ ਦੇਖਣ ਲਈ ਸਥਿਰ • [SoundCloud] ਅੱਪਡੇਟ ਕੀਤਾ client_id
+ਨਵਾਂ
+• ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲਦੇ ਸਮੇਂ ਲਾਕ ਸਕ੍ਰੀਨ 'ਤੇ ਵੀਡੀਓ ਥੰਬਨੇਲ ਦਿਖਾਓ
+
+ਸੁਧਾਰਿਆ ਗਿਆ
+• ਬੈਕਗ੍ਰਾਊਂਡ/ਪੌਪਅੱਪ ਬਟਨ ਨੂੰ ਦੇਰ ਤੱਕ ਦਬਾਉਣ 'ਤੇ ਸਥਾਨਕ ਪਲੇਲਿਸਟਾਂ ਨੂੰ ਕਤਾਰ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ
+• [YouTube] /c/shortened_url ਚੈਨਲ ਲਿੰਕਾਂ ਲਈ ਸਮਰਥਨ ਸ਼ਾਮਲ ਕਰੋ
+
+ਠੀਕ ਕੀਤਾ ਗਿਆ
+• NewPipe 'ਤੇ ਵੀਡੀਓ ਸਾਂਝੇ ਕਰਨ ਅਤੇ ਉਹਨਾਂ ਦੀਆਂ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਸਿੱਧਾ ਡਾਊਨਲੋਡ ਕਰਨ ਵੇਲੇ ਕਈ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਹੱਲ ਕੀਤਾ ਗਿਆ
+• ਖੋਜ ਨਤੀਜਿਆਂ ਦੀ ਪੇਜਿੰਗ ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ
+• [SoundCloud] client_id ਨੂੰ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ
diff --git a/fastlane/metadata/android/pa/changelogs/840.txt b/fastlane/metadata/android/pa/changelogs/840.txt
index 745098496..d05907bd6 100644
--- a/fastlane/metadata/android/pa/changelogs/840.txt
+++ b/fastlane/metadata/android/pa/changelogs/840.txt
@@ -1 +1,10 @@
-ਨਵਾਂ • ਐਪ ਦੀ ਭਾਸ਼ਾ ਬਦਲਣ ਲਈ ਭਾਸ਼ਾ ਚੋਣਕਾਰ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ • ਪਲੇਅਰ ਸਮੇਟਣਯੋਗ ਮੀਨੂ ਵਿੱਚ ਕੋਡੀ ਬਟਨ 'ਤੇ ਭੇਜੋ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ • ਲੰਬੀ ਪ੍ਰੈਸ 'ਤੇ ਟਿੱਪਣੀਆਂ ਨੂੰ ਕਾਪੀ ਕਰਨ ਦੀ ਸਮਰੱਥਾ ਸ਼ਾਮਲ ਕੀਤੀ ਗਈ ਹੈ ਸੁਧਾਰ • ਰੀਕੈਪਚਾ ਗਤੀਵਿਧੀ ਨੂੰ ਠੀਕ ਕਰੋ ਅਤੇ ਪ੍ਰਾਪਤ ਕੀਤੀਆਂ ਕੂਕੀਜ਼ ਨੂੰ ਸਹੀ ਢੰਗ ਨਾਲ ਸੁਰੱਖਿਅਤ ਕਰੋ • ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਦੇਖਣ ਦਾ ਇਤਿਹਾਸ ਚਾਲੂ ਨਾ ਹੋਣ 'ਤੇ ਦਰਾਜ਼ ਦੇ ਹੱਕ ਵਿੱਚ ਡਾਟ-ਮੀਨੂ ਨੂੰ ਹਟਾਇਆ ਗਿਆ ਅਤੇ ਇਤਿਹਾਸ ਨੂੰ ਲੁਕਾਓ ਬਟਨ • Android 6 ਅਤੇ ਬਾਅਦ ਵਾਲੇ 'ਤੇ ਸਹੀ ਢੰਗ ਨਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਹੋਰ ਐਪਾਂ ਦੀ ਇਜਾਜ਼ਤ ਦੇ ਉੱਪਰ ਡਿਸਪਲੇ ਲਈ ਪੁੱਛੋ • BookmarkFragment ਵਿੱਚ ਲੰਮਾ-ਕਲਿੱਕ ਕਰਕੇ ਸਥਾਨਕ ਪਲੇਲਿਸਟ ਦਾ ਨਾਮ ਬਦਲੋ • ਕਈ PeerTube ਸੁਧਾਰ • ਕਈ ਅੰਗਰੇਜ਼ੀ ਸਰੋਤ ਸਤਰਾਂ ਨੂੰ ਸੁਧਾਰਿਆ ਗਿਆ ਹੈ ਸਥਿਰ • ਫਿਕਸਡ ਪਲੇਅਰ ਦੁਬਾਰਾ ਸ਼ੁਰੂ ਹੋ ਰਿਹਾ ਹੈ ਹਾਲਾਂਕਿ ਇਹ ਉਦੋਂ ਰੋਕਿਆ ਜਾਂਦਾ ਹੈ ਜਦੋਂ ਵਿਕਲਪ "ਐਪ ਸਵਿੱਚ 'ਤੇ ਛੋਟਾ ਕਰੋ" ਯੋਗ ਕੀਤਾ ਜਾਂਦਾ ਹੈ ਅਤੇ ਨਿਊ ਪਾਈਪ ਨੂੰ ਛੋਟਾ ਕੀਤਾ ਜਾਂਦਾ ਹੈ • ਸੰਕੇਤ ਲਈ ਸ਼ੁਰੂਆਤੀ ਚਮਕ ਮੁੱਲ ਨੂੰ ਠੀਕ ਕਰੋ • ਸਥਿਰ .srt ਉਪਸਿਰਲੇਖ ਡਾਉਨਲੋਡ ਜਿਸ ਵਿੱਚ ਸਾਰੇ ਲਾਈਨ ਬ੍ਰੇਕ ਨਹੀਂ ਹਨ • SD ਕਾਰਡ 'ਤੇ ਸਥਿਰ ਡਾਊਨਲੋਡ ਅਸਫਲ ਹੋ ਰਿਹਾ ਹੈ ਕਿਉਂਕਿ ਕੁਝ Android 5 ਡਿਵਾਈਸਾਂ CTF ਅਨੁਕੂਲ ਨਹੀਂ ਹਨ • Android KitKat 'ਤੇ ਸਥਿਰ ਡਾਊਨਲੋਡਿੰਗ • ਸਥਿਰ ਭ੍ਰਿਸ਼ਟ ਵੀਡੀਓ .mp4 ਫਾਈਲ ਨੂੰ ਆਡੀਓ ਫਾਈਲ ਵਜੋਂ ਮਾਨਤਾ ਦਿੱਤੀ ਜਾ ਰਹੀ ਹੈ • ਗਲਤ ਚੀਨੀ ਭਾਸ਼ਾ ਕੋਡ ਸਮੇਤ, ਮਲਟੀਪਲ ਸਥਾਨੀਕਰਨ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਹੱਲ ਕੀਤਾ ਗਿਆ ਹੈ • [YouTube] ਵਰਣਨ ਵਿੱਚ ਟਾਈਮਸਟੈਂਪ ਦੁਬਾਰਾ ਕਲਿੱਕ ਕਰਨ ਯੋਗ ਹਨ
+ਨਵਾਂ
+• ਐਪ ਦੀ ਭਾਸ਼ਾ ਬਦਲਣ ਲਈ ਇੱਕ ਭਾਸ਼ਾ ਚੋਣਕਾਰ ਜੋੜਿਆ ਗਿਆ
+• ਪਲੇਅਰ ਦੇ ਕੋਲੈਪਸੀਬਲ ਮੀਨੂ ਵਿੱਚ ਕੋਡੀ ਨੂੰ ਭੇਜੋ ਬਟਨ ਜੋੜਿਆ ਗਿਆ
+• ਟਿੱਪਣੀਆਂ ਦੀ ਕਾਪੀ ਕਰਨ ਲਈ ਇੱਕ ਲੰਮਾ-ਦਬਾਓ ਵਿਸ਼ੇਸ਼ਤਾ ਜੋੜਿਆ ਗਿਆ
+
+ਸੁਧਾਰਿਆ ਗਿਆ
+• ਰੀਕੈਪਚਾ ਗਤੀਵਿਧੀ ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ ਅਤੇ ਪ੍ਰਾਪਤ ਕੂਕੀਜ਼ ਨੂੰ ਸਹੀ ਢੰਗ ਨਾਲ ਸੁਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ
+
+ਠੀਕ ਕੀਤਾ ਗਿਆ
+• ਐਂਡਰਾਇਡ ਕਿਟਕੈਟ 'ਤੇ ਡਾਊਨਲੋਡਿੰਗ ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ
diff --git a/fastlane/metadata/android/pa/changelogs/920.txt b/fastlane/metadata/android/pa/changelogs/920.txt
index 04fc07937..94b1e74a0 100644
--- a/fastlane/metadata/android/pa/changelogs/920.txt
+++ b/fastlane/metadata/android/pa/changelogs/920.txt
@@ -1 +1,9 @@
-ਸੁਧਾਰ • ਸਟ੍ਰੀਮ ਗਰਿੱਡ ਆਈਟਮਾਂ 'ਤੇ ਅੱਪਲੋਡ ਦੀ ਮਿਤੀ ਅਤੇ ਦੇਖਣ ਦੀ ਗਿਣਤੀ ਸ਼ਾਮਲ ਕੀਤੀ ਗਈ • ਦਰਾਜ਼ ਹੈਡਰ ਲੇਆਉਟ ਲਈ ਸੁਧਾਰ ਸਥਿਰ • ਏਪੀਆਈ 19 'ਤੇ ਕ੍ਰੈਸ਼ ਹੋਣ ਕਾਰਨ ਫਿਕਸਡ ਮਿਊਟ ਬਟਨ • ਲੰਬੇ 1080p 60fps ਵੀਡੀਓ ਦੀ ਸਥਿਰ ਡਾਊਨਲੋਡਿੰਗ
+ਸੁਧਾਰਿਆ ਗਿਆ
+
+• ਸਟ੍ਰੀਮ ਗਰਿੱਡ ਆਈਟਮਾਂ 'ਤੇ ਅਪਲੋਡ ਮਿਤੀ ਅਤੇ ਵਿਯੂ ਗਿਣਤੀ ਸ਼ਾਮਲ ਕੀਤੀ ਗਈ
+• ਦਰਾਜ਼ ਹੈਡਰ ਲੇਆਉਟ ਲਈ ਸੁਧਾਰ
+
+ਠੀਕ ਕੀਤਾ ਗਿਆ
+
+• API 19 'ਤੇ ਕਰੈਸ਼ ਹੋਣ ਵਾਲੇ ਮਿਊਟ ਬਟਨ ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ
+• ਲੰਬੇ 1080p 60fps ਵੀਡੀਓਜ਼ ਨੂੰ ਡਾਊਨਲੋਡ ਕਰਨਾ ਠੀਕ ਕੀਤਾ ਗਿਆ
diff --git a/fastlane/metadata/android/pa/changelogs/930.txt b/fastlane/metadata/android/pa/changelogs/930.txt
index a067bfb58..96fc7d0b5 100644
--- a/fastlane/metadata/android/pa/changelogs/930.txt
+++ b/fastlane/metadata/android/pa/changelogs/930.txt
@@ -1 +1,14 @@
-ਨਵਾਂ • YouTube ਸੰਗੀਤ 'ਤੇ ਖੋਜੋ • ਬੁਨਿਆਦੀ Android TV ਸਮਰਥਨ ਸੁਧਾਰ • ਇੱਕ ਸਥਾਨਕ ਪਲੇਲਿਸਟ ਤੋਂ ਸਾਰੇ ਦੇਖੇ ਗਏ ਵੀਡੀਓ ਨੂੰ ਹਟਾਉਣ ਦੀ ਯੋਗਤਾ ਸ਼ਾਮਲ ਕੀਤੀ ਗਈ ਹੈ • ਕ੍ਰੈਸ਼ ਹੋਣ ਦੀ ਬਜਾਏ ਜਦੋਂ ਸਮੱਗਰੀ ਅਜੇ ਸਮਰਥਿਤ ਨਹੀਂ ਹੈ ਤਾਂ ਸੁਨੇਹਾ ਦਿਖਾਓ • ਚੁਟਕੀ ਇਸ਼ਾਰਿਆਂ ਨਾਲ ਪੌਪਅੱਪ ਪਲੇਅਰ ਦਾ ਆਕਾਰ ਬਦਲਿਆ ਗਿਆ ਹੈ • ਬੈਕਗ੍ਰਾਊਂਡ 'ਤੇ ਲੰਬੇ ਸਮੇਂ ਤੱਕ ਦਬਾਉਣ ਅਤੇ ਚੈਨਲ ਵਿੱਚ ਪੌਪਅੱਪ ਬਟਨਾਂ 'ਤੇ ਸਟ੍ਰੀਮ ਨੂੰ ਐਨਕਿਊ ਕਰੋ • ਦਰਾਜ਼ ਸਿਰਲੇਖ ਦੇ ਸਿਰਲੇਖ ਦੇ ਆਕਾਰ ਨੂੰ ਸੰਭਾਲਣ ਵਿੱਚ ਸੁਧਾਰ ਕੀਤਾ ਗਿਆ ਹੈ ਸਥਿਰ • ਨਿਸ਼ਚਿਤ ਉਮਰ ਪ੍ਰਤਿਬੰਧਿਤ ਸਮੱਗਰੀ ਸੈਟਿੰਗ ਕੰਮ ਨਹੀਂ ਕਰ ਰਹੀ • ਕੁਝ ਖਾਸ ਕਿਸਮ ਦੇ reCAPTCHA ਫਿਕਸ ਕੀਤੇ ਗਏ ਹਨ • ਪਲੇਲਿਸਟ `ਨੱਲ` ਹੋਣ 'ਤੇ ਬੁੱਕਮਾਰਕ ਖੋਲ੍ਹਣ ਵੇਲੇ ਸਥਿਰ ਕਰੈਸ਼ • ਨੈੱਟਵਰਕ ਸੰਬੰਧੀ ਅਪਵਾਦਾਂ ਦੀ ਸਥਿਰ ਖੋਜ • ਸਬਸਕ੍ਰਿਪਸ਼ਨ ਫਰੈਗਮੈਂਟ ਵਿੱਚ ਗਰੁੱਪ ਸੌਰਟ ਬਟਨ ਦੀ ਸਥਿਰ ਦਿੱਖ ਅਤੇ ਹੋਰ
+ਨਵਾਂ
+• YouTube ਸੰਗੀਤ ਖੋਜੋ
+• ਮੁੱਢਲਾ Android TV ਸਮਰਥਨ
+
+ਸੁਧਾਰਿਆ ਗਿਆ
+• ਸਥਾਨਕ ਪਲੇਲਿਸਟਾਂ ਤੋਂ ਸਾਰੇ ਦੇਖੇ ਗਏ ਵੀਡੀਓ ਹਟਾਉਣ ਦੀ ਯੋਗਤਾ ਸ਼ਾਮਲ ਕੀਤੀ ਗਈ
+• ਜਦੋਂ ਸਮੱਗਰੀ ਵਰਤਮਾਨ ਵਿੱਚ ਸਮਰਥਿਤ ਨਹੀਂ ਹੈ ਤਾਂ ਕ੍ਰੈਸ਼ ਹੋਣ ਦੀ ਬਜਾਏ ਇੱਕ ਸੁਨੇਹਾ ਦਿਖਾਓ
+
+ਠੀਕ ਕੀਤਾ ਗਿਆ
+• ਉਮਰ-ਪ੍ਰਤੀਬੰਧਿਤ ਸਮੱਗਰੀ ਸੈਟਿੰਗਾਂ ਨਾਲ ਇੱਕ ਸਮੱਸਿਆ ਨੂੰ ਹੱਲ ਕੀਤਾ ਗਿਆ।
+
+ਕੁਝ reCAPTCHA ਗਲਤੀਆਂ ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ।
+
+ਅਤੇ ਹੋਰ ਵੀ
diff --git a/fastlane/metadata/android/pa/changelogs/940.txt b/fastlane/metadata/android/pa/changelogs/940.txt
index b9d9b3fdf..3ea03ad03 100644
--- a/fastlane/metadata/android/pa/changelogs/940.txt
+++ b/fastlane/metadata/android/pa/changelogs/940.txt
@@ -1 +1,14 @@
-ਨਵਾਂ • SoundCloud ਟਿੱਪਣੀਆਂ ਲਈ ਸਮਰਥਨ ਸ਼ਾਮਲ ਕਰੋ • YouTube ਪ੍ਰਤਿਬੰਧਿਤ ਮੋਡ ਸੈਟਿੰਗ ਸ਼ਾਮਲ ਕਰੋ • PeerTube ਮੂਲ ਚੈਨਲ ਦੇ ਵੇਰਵੇ ਦਿਖਾਓ ਸੁਧਾਰ • ਸਿਰਫ਼ ਸਮਰਥਿਤ ਸੇਵਾਵਾਂ ਲਈ ਕੋਰ ਬਟਨ ਦਿਖਾਓ • ਨੈਵੀਗੇਸ਼ਨਬਾਰ ਜਾਂ ਸਟੇਟਸਬਾਰ ਤੋਂ ਸ਼ੁਰੂ ਹੋਣ ਵਾਲੇ ਪਲੇਅਰ ਸੰਕੇਤਾਂ ਨੂੰ ਬਲਾਕ ਕਰੋ • ਸੇਵਾ ਦੇ ਰੰਗ ਦੇ ਆਧਾਰ 'ਤੇ ਮੁੜ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਅਤੇ ਗਾਹਕ ਬਣੋ ਬਟਨਾਂ ਦਾ ਪਿਛੋਕੜ ਰੰਗ ਬਦਲੋ ਸਥਿਰ • ਡਾਉਨਲੋਡ ਡਾਇਲਾਗ ਫ੍ਰੀਜ਼ ਨੂੰ ਠੀਕ ਕਰੋ • ਬ੍ਰਾਊਜ਼ਰ ਵਿੱਚ ਖੋਲ੍ਹੋ ਬਟਨ ਹੁਣ ਅਸਲ ਵਿੱਚ ਬ੍ਰਾਊਜ਼ਰ ਵਿੱਚ ਖੁੱਲ੍ਹਦਾ ਹੈ • ਵੀਡੀਓ ਖੋਲ੍ਹਣ 'ਤੇ ਕ੍ਰੈਸ਼ ਨੂੰ ਠੀਕ ਕਰੋ ਅਤੇ "ਇਸ ਸਟ੍ਰੀਮ ਨੂੰ ਚਲਾਇਆ ਨਹੀਂ ਜਾ ਸਕਿਆ" ਅਤੇ ਹੋਰ
+ਨਵਾਂ
+• SoundCloud ਟਿੱਪਣੀਆਂ ਲਈ ਸਮਰਥਨ ਸ਼ਾਮਲ ਕਰੋ
+• YouTube ਪ੍ਰਤਿਬੰਧਿਤ ਮੋਡ ਸੈਟਿੰਗ ਸ਼ਾਮਲ ਕਰੋ
+• PeerTube ਪੇਰੈਂਟ ਚੈਨਲ ਵੇਰਵੇ ਦਿਖਾਓ
+
+ਸੁਧਾਰਿਆ ਗਿਆ
+• ਸਿਰਫ਼ ਸਮਰਥਿਤ ਸੇਵਾਵਾਂ ਲਈ Kore ਬਟਨ ਦਿਖਾਓ
+
+ਠੀਕ ਕੀਤਾ ਗਿਆ
+• ਇੱਕ ਸਮੱਸਿਆ ਨੂੰ ਹੱਲ ਕੀਤਾ ਗਿਆ ਜਿੱਥੇ ਡਾਊਨਲੋਡ ਡਾਇਲਾਗ ਫ੍ਰੀਜ਼ ਹੋ ਰਿਹਾ ਸੀ
+• ਬ੍ਰਾਊਜ਼ਰ ਵਿੱਚ ਖੋਲ੍ਹੋ ਬਟਨ ਹੁਣ ਅਸਲ ਵਿੱਚ ਬ੍ਰਾਊਜ਼ਰ ਵਿੱਚ ਖੁੱਲ੍ਹਦਾ ਹੈ
+• ਵੀਡੀਓ ਖੋਲ੍ਹਣ ਵੇਲੇ ਕਰੈਸ਼ ਅਤੇ "ਇਸ ਸਟ੍ਰੀਮ ਨੂੰ ਚਲਾਇਆ ਨਹੀਂ ਜਾ ਸਕਿਆ"
+
+ਅਤੇ ਹੋਰ
diff --git a/fastlane/metadata/android/pa/changelogs/951.txt b/fastlane/metadata/android/pa/changelogs/951.txt
index 2b1cd7933..f4dd14071 100644
--- a/fastlane/metadata/android/pa/changelogs/951.txt
+++ b/fastlane/metadata/android/pa/changelogs/951.txt
@@ -1,13 +1,13 @@
-ਨਵਾਂ
-• ਫੀਡ ਗਰੁੱਪ ਡਾਇਲਾਗ ਵਿੱਚ ਗਾਹਕੀ ਚੋਣਕਾਰ ਲਈ ਖੋਜ ਸ਼ਾਮਲ ਕਰੋ
-• ਸਿਰਫ਼ ਗੈਰ-ਗਰੁੱਪ ਕੀਤੀਆਂ ਗਾਹਕੀਆਂ ਨੂੰ ਦਿਖਾਉਣ ਲਈ ਫੀਡ ਗਰੁੱਪ ਡਾਇਲਾਗ ਵਿੱਚ ਫਿਲਟਰ ਸ਼ਾਮਲ ਕਰੋ
-• ਪਲੇਲਿਸਟ ਟੈਬ ਨੂੰ ਮੁੱਖ ਪੰਨੇ 'ਤੇ ਸ਼ਾਮਲ ਕਰੋ
-• ਬੈਕਗ੍ਰਾਊਂਡ/ਪੌਪ-ਅੱਪ ਪਲੇਅਰ ਕਤਾਰ ਵਿੱਚ ਤੇਜ਼ੀ ਨਾਲ ਅੱਗੇ/ਰਿਵਾਈਂਡ ਕਰੋ
-• ਖੋਜ ਸੁਝਾਅ ਪ੍ਰਦਰਸ਼ਿਤ ਕਰੋ: ਕੀ ਤੁਹਾਡਾ ਮਤਲਬ ਹੈ ਅਤੇ ਇਸ ਲਈ ਨਤੀਜਾ ਦਿਖਾ ਰਿਹਾ ਹੈ
-ਸੁਧਾਰ
-• ਮਿਕਸਡ ਫਾਈਲਾਂ ਵਿੱਚ ਐਪਲੀਕੇਸ਼ਨ ਮੈਟਾਡੇਟਾ ਲਿਖਣਾ ਛੱਡੋ • ਕਤਾਰ ਤੋਂ ਅਸਫਲ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਨਾ ਹਟਾਓ
-• ਟੂਲਬਾਰ ਦੇ ਰੰਗ ਨਾਲ ਮੇਲ ਕਰਨ ਲਈ ਸਥਿਤੀ ਪੱਟੀ ਦਾ ਰੰਗ ਅੱਪਡੇਟ ਕਰੋ
+ਨਵਾਂ
+• ਫੀਡ ਗਰੁੱਪ ਡਾਇਲਾਗ ਵਿੱਚ ਸਬਸਕ੍ਰਿਪਸ਼ਨ ਚੋਣਕਾਰ ਲਈ ਖੋਜ ਸ਼ਾਮਲ ਕੀਤੀ ਗਈ
+• ਸਿਰਫ਼ ਅਣ-ਗਰੁੱਪ ਕੀਤੀਆਂ ਗਾਹਕੀਆਂ ਦਿਖਾਉਣ ਲਈ ਫੀਡ ਗਰੁੱਪ ਡਾਇਲਾਗ ਵਿੱਚ ਇੱਕ ਫਿਲਟਰ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ
+• ਮੁੱਖ ਪੰਨੇ 'ਤੇ ਇੱਕ ਪਲੇਲਿਸਟ ਟੈਬ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ
-ਠੀਕ ਕੀਤਾ
-• ਫਲੋਟਿੰਗ ਪੁਆਇੰਟ ਸੰਚਤ ਤਰੁੱਟੀਆਂ ਦੇ ਕਾਰਨ ਫਿਕਸਡ ਆਡੀਓ/ਵੀਡੀਓ ਡੀਸਿੰਕ
-• [PeerTube] ਮਿਟਾਈਆਂ ਗਈਆਂ ਟਿੱਪਣੀਆਂ ਨੂੰ ਸੰਭਾਲੋ ਅਤੇ ਹੋਰ
+ਸੁਧਾਰਿਆ ਗਿਆ
+• ਮਕਸਡ ਫਾਈਲਾਂ ਵਿੱਚ ਐਪਲੀਕੇਸ਼ਨ ਮੈਟਾਡੇਟਾ ਲਿਖਣਾ ਬੰਦ ਕੀਤਾ ਗਿਆ
+• ਕਤਾਰ ਤੋਂ ਅਸਫਲ ਸਟ੍ਰੀਮਾਂ ਨੂੰ ਨਾ ਹਟਾਓ
+
+ਠੀਕ ਕੀਤਾ ਗਿਆ
+• ਫਲੋਟਿੰਗ ਪੁਆਇੰਟ ਸੰਚਤ ਗਲਤੀਆਂ ਕਾਰਨ ਆਡੀਓ/ਵੀਡੀਓ ਡੀਸਿੰਕ ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ
+
+ਅਤੇ ਹੋਰ
diff --git a/fastlane/metadata/android/pa/changelogs/954.txt b/fastlane/metadata/android/pa/changelogs/954.txt
index 3eb8dd68b..b5b0e78d8 100644
--- a/fastlane/metadata/android/pa/changelogs/954.txt
+++ b/fastlane/metadata/android/pa/changelogs/954.txt
@@ -1,8 +1,9 @@
-• ਨਵਾਂ ਐਪਲੀਕੇਸ਼ਨ ਵਰਕਫਲੋ: ਵੇਰਵੇ ਵਾਲੇ ਪੰਨੇ 'ਤੇ ਵੀਡੀਓ ਚਲਾਓ, ਪਲੇਅਰ ਨੂੰ ਛੋਟਾ ਕਰਨ ਲਈ ਹੇਠਾਂ ਵੱਲ ਸਵਾਈਪ ਕਰੋ
-• ਮੀਡੀਆ ਸਟਾਈਲ ਸੂਚਨਾਵਾਂ: ਸੂਚਨਾਵਾਂ ਵਿੱਚ ਅਨੁਕੂਲਿਤ ਕਾਰਵਾਈਆਂ, ਪ੍ਰਦਰਸ਼ਨ ਸੁਧਾਰ
-• ਡੈਸਕਟੌਪ ਐਪ ਦੇ ਤੌਰ 'ਤੇ NewPipe ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਸਮੇਂ ਮੂਲ ਰੀਸਾਈਜ਼ ਕਰਨਾ
+• ਨਵਾਂ ਐਪ ਵਰਕਫਲੋ: ਵੇਰਵੇ ਵਾਲੇ ਪੰਨੇ 'ਤੇ ਵੀਡੀਓ ਚਲਾਓ, ਪਲੇਅਰ ਨੂੰ ਛੋਟਾ ਕਰਨ ਲਈ ਹੇਠਾਂ ਵੱਲ ਸਵਾਈਪ ਕਰੋ
+• ਮੀਡੀਆਸਟਾਈਲ ਸੂਚਨਾਵਾਂ: ਸੂਚਨਾਵਾਂ ਵਿੱਚ ਅਨੁਕੂਲਿਤ ਕਾਰਵਾਈਆਂ, ਪ੍ਰਦਰਸ਼ਨ ਸੁਧਾਰ
+• ਡੈਸਕਟੌਪ ਐਪ ਦੇ ਤੌਰ 'ਤੇ NewPipe ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਸਮੇਂ ਮੂਲ ਆਕਾਰ ਬਦਲਣਾ
-• ਇੱਕ ਅਸਮਰਥਿਤ URL ਟੋਸਟ ਦੇ ਮਾਮਲੇ ਵਿੱਚ ਖੁੱਲੇ ਵਿਕਲਪਾਂ ਨਾਲ ਡਾਇਲਾਗ ਦਿਖਾਓ
-• ਜਦੋਂ ਰਿਮੋਟ ਨੂੰ ਪ੍ਰਾਪਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ ਤਾਂ ਖੋਜ ਸੁਝਾਅ ਅਨੁਭਵ ਨੂੰ ਬਿਹਤਰ ਬਣਾਓ
-• ਡਿਫ਼ਾਲਟ ਵੀਡੀਓ ਗੁਣਵੱਤਾ ਨੂੰ 720p60 (ਇਨ-ਐਪ ਪਲੇਅਰ) ਅਤੇ 480p (ਪੌਪ-ਅੱਪ ਪਲੇਅਰ) ਤੱਕ ਵਧਾ ਦਿੱਤਾ ਗਿਆ ਹੈ
-• ਬਹੁਤ ਸਾਰੇ ਬੱਗ ਫਿਕਸ ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ
+• ਇੱਕ ਅਸਮਰਥਿਤ URL ਟੋਸਟ ਦੀ ਸਥਿਤੀ ਵਿੱਚ ਖੁੱਲ੍ਹੇ ਵਿਕਲਪਾਂ ਦੇ ਨਾਲ ਇੱਕ ਡਾਇਲਾਗ ਦਿਖਾਓ
+• ਰਿਮੋਟ ਸੁਝਾਅ ਉਪਲਬਧ ਨਾ ਹੋਣ 'ਤੇ ਸੁਧਾਰਾਂ ਦਾ ਅਨੁਭਵ ਕਰੋ
+• ਡਿਫੌਲਟ ਵੀਡੀਓ ਗੁਣਵੱਤਾ 720p60 (ਇਨ-ਐਪ ਪਲੇਅਰ) ਅਤੇ 480p (ਪੌਪ-ਅੱਪ ਪਲੇਅਰ) ਤੱਕ ਵਧਾ ਦਿੱਤੀ ਗਈ
+
+• ਬੱਗ ਫਿਕਸ ਅਤੇ ਹੋਰ ਬਹੁਤ ਕੁਝ
diff --git a/fastlane/metadata/android/pa/changelogs/957.txt b/fastlane/metadata/android/pa/changelogs/957.txt
index eb66dacbc..2cf56525d 100644
--- a/fastlane/metadata/android/pa/changelogs/957.txt
+++ b/fastlane/metadata/android/pa/changelogs/957.txt
@@ -1,10 +1,7 @@
-• ਖਾਸ ਐਨਕਿਊ ਕਿਰਿਆਵਾਂ ਨੂੰ ਇੱਕ ਵਿੱਚ ਜੋੜੋ
-• ਪਲੇਅਰ ਨੂੰ ਬੰਦ ਕਰਨ ਲਈ ਦੋ ਉਂਗਲਾਂ ਦੇ ਸੰਕੇਤ
-• reCAPTCHA ਕੂਕੀਜ਼ ਨੂੰ ਕਲੀਅਰ ਕਰਨ ਦਿਓ
-• ਨੋਟੀਫਿਕੇਸ਼ਨ ਨੂੰ ਰੰਗ ਨਾ ਕਰਨ ਦਾ ਵਿਕਲਪ
-• ਅਨੰਤ ਬਫਰਿੰਗ ਨੂੰ ਠੀਕ ਕਰਨ ਲਈ ਵਿਡੀਓ ਵੇਰਵਿਆਂ ਨੂੰ ਕਿਵੇਂ ਖੋਲ੍ਹਿਆ ਜਾਂਦਾ ਹੈ ਇਸ ਵਿੱਚ ਸੁਧਾਰ ਕਰੋ, ਨਿਊਪਾਈਪ ਨਾਲ ਸਾਂਝਾ ਕਰਨ ਵੇਲੇ ਬੱਗੀ ਵਿਵਹਾਰ ਅਤੇ ਹੋਰ ਅਸੰਗਤਤਾਵਾਂ
-• YouTube ਵੀਡੀਓਜ਼ ਦੀ ਗਤੀ ਵਧਾਓ ਅਤੇ ਉਮਰ ਪ੍ਰਤੀਬੰਧਿਤ ਵੀਡੀਓ ਨੂੰ ਠੀਕ ਕਰੋ
-• ਫਾਸਟ ਫਾਰਵਰਡ/ਰਿਵਾਇੰਡ 'ਤੇ ਕਰੈਸ਼ ਨੂੰ ਠੀਕ ਕਰੋ
-• ਥੰਬਨੇਲ ਖਿੱਚ ਕੇ ਸੂਚੀਆਂ ਨੂੰ ਮੁੜ ਵਿਵਸਥਿਤ ਨਾ ਕਰੋ
-• ਪੌਪਅੱਪ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਹਮੇਸ਼ਾ ਯਾਦ ਰੱਖੋ
-• ਸੰਤਾਲੀ ਭਾਸ਼ਾ ਸ਼ਾਮਲ ਕਰੋ
+• ਖਾਸ NQE ਕਿਰਿਆਵਾਂ ਨੂੰ ਇੱਕ ਵਿੱਚ ਏਕੀਕ੍ਰਿਤ ਕਰਨਾ।
+• ਦੋ-ਉਂਗਲਾਂ ਵਾਲੇ ਇਸ਼ਾਰੇ ਨਾਲ ਵੀਡੀਓ ਪਲੇਅਰ ਨੂੰ ਬੰਦ ਕਰਨਾ।
+• reCOPTCHA ਕੂਕੀਜ਼ ਨੂੰ ਹਟਾਉਣ ਦੀ ਆਗਿਆ ਦੇਣਾ।
+• ਸੂਚਨਾਵਾਂ ਨੂੰ ਰੰਗੀਨ ਨਾ ਕਰਨ ਦਾ ਵਿਕਲਪ।
+• NewPipe 'ਤੇ ਸਾਂਝਾ ਕਰਦੇ ਸਮੇਂ ਅਨੰਤ ਬਫਰਿੰਗ, ਗਲਤੀਆਂ ਅਤੇ ਹੋਰ ਅਸੰਗਤੀਆਂ ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ।
+• YouTube ਵੀਡੀਓ ਨੂੰ ਤੇਜ਼ ਕੀਤਾ ਗਿਆ ਅਤੇ ਉਮਰ-ਪ੍ਰਤੀਬੰਧਿਤ ਵੀਡੀਓ ਨੂੰ ਬਿਹਤਰ ਬਣਾਇਆ ਗਿਆ।
+• ਫਾਸਟ ਫਾਰਵਰਡ/ਰਿਵਾਈਂਡ 'ਤੇ ਕਰੈਸ਼ਾਂ ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ
diff --git a/fastlane/metadata/android/pa/changelogs/964.txt b/fastlane/metadata/android/pa/changelogs/964.txt
index 85dc2c151..e94595673 100644
--- a/fastlane/metadata/android/pa/changelogs/964.txt
+++ b/fastlane/metadata/android/pa/changelogs/964.txt
@@ -1 +1,6 @@
-• ਪਲੇਅਰ ਨਿਯੰਤਰਣ ਵਿੱਚ ਅਧਿਆਵਾਂ ਲਈ ਸਮਰਥਨ ਜੋੜਿਆ ਗਿਆ • [PeerTube] ਸੇਪੀਆ ਖੋਜ ਸ਼ਾਮਲ ਕੀਤੀ ਗਈ • ਵੀਡੀਓ ਵੇਰਵੇ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਸ਼ੇਅਰ ਬਟਨ ਨੂੰ ਮੁੜ-ਜੋੜਿਆ ਗਿਆ ਅਤੇ ਟੈਬ ਲੇਆਉਟ ਵਿੱਚ ਸਟ੍ਰੀਮ ਵਰਣਨ ਨੂੰ ਤਬਦੀਲ ਕੀਤਾ ਗਿਆ • ਜੇਕਰ ਚਮਕ ਦਾ ਸੰਕੇਤ ਅਸਮਰੱਥ ਹੈ ਤਾਂ ਚਮਕ ਨੂੰ ਬਹਾਲ ਕਰਨਾ ਬੰਦ ਕਰੋ • ਕੋਡੀ 'ਤੇ ਵੀਡੀਓ ਚਲਾਉਣ ਲਈ ਸੂਚੀ ਆਈਟਮ ਸ਼ਾਮਲ ਕੀਤੀ ਗਈ • ਕੁਝ ਡਿਵਾਈਸਾਂ 'ਤੇ ਕੋਈ ਡਿਫੌਲਟ ਬ੍ਰਾਊਜ਼ਰ ਸੈੱਟ ਨਾ ਹੋਣ 'ਤੇ ਕ੍ਰੈਸ਼ ਦਾ ਹੱਲ ਕੀਤਾ ਗਿਆ ਹੈ ਅਤੇ ਸ਼ੇਅਰ ਡਾਇਲਾਗਸ ਨੂੰ ਬਿਹਤਰ ਬਣਾਓ • ਫੁੱਲਸਕ੍ਰੀਨ ਪਲੇਅਰ ਵਿੱਚ ਹਾਰਡਵੇਅਰ ਸਪੇਸ ਬਟਨ ਨਾਲ ਪਲੇ/ਪੌਜ਼ ਨੂੰ ਟੌਗਲ ਕਰੋ • [media.ccc.de] ਕਈ ਫਿਕਸ ਅਤੇ ਸੁਧਾਰ
+• ਪਲੇਅਰ ਕੰਟਰੋਲਾਂ ਵਿੱਚ ਚੈਪਟਰਾਂ ਲਈ ਸਮਰਥਨ ਜੋੜਿਆ ਗਿਆ
+• [PeerTube] ਸੇਪੀਆ ਖੋਜ ਜੋੜਿਆ ਗਿਆ
+• ਵੀਡੀਓ ਵੇਰਵੇ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਸ਼ੇਅਰ ਬਟਨ ਨੂੰ ਦੁਬਾਰਾ ਜੋੜਿਆ ਗਿਆ ਅਤੇ ਸਟ੍ਰੀਮ ਵਰਣਨ ਨੂੰ ਟੈਬ ਲੇਆਉਟ ਵਿੱਚ ਤਬਦੀਲ ਕੀਤਾ ਗਿਆ
+• ਜੇਕਰ ਚਮਕ ਸੰਕੇਤ ਅਯੋਗ ਹੈ ਤਾਂ ਚਮਕ ਨੂੰ ਬਹਾਲ ਕਰਨਾ ਅਯੋਗ ਕਰੋ
+• ਕੋਡੀ 'ਤੇ ਵੀਡੀਓ ਚਲਾਉਣ ਲਈ ਸੂਚੀ ਆਈਟਮ ਸ਼ਾਮਲ ਕੀਤੀ ਗਈ
+• ਕੁਝ ਡਿਵਾਈਸਾਂ 'ਤੇ ਕੋਈ ਡਿਫੌਲਟ ਬ੍ਰਾਊਜ਼ਰ ਸੈੱਟ ਨਾ ਹੋਣ 'ਤੇ ਕਰੈਸ਼ ਨੂੰ ਠੀਕ ਕੀਤਾ ਗਿਆ
diff --git a/fastlane/metadata/android/pa/changelogs/975.txt b/fastlane/metadata/android/pa/changelogs/975.txt
index c866df1e2..fe23991c7 100644
--- a/fastlane/metadata/android/pa/changelogs/975.txt
+++ b/fastlane/metadata/android/pa/changelogs/975.txt
@@ -3,14 +3,11 @@
• ਅਯੋਗ ਟਿੱਪਣੀਆਂ ਦਾ ਪਤਾ ਲਗਾਓ
• ਫੀਡ ਆਈਟਮ ਨੂੰ ਦੇਖੇ ਗਏ ਵਜੋਂ ਨਿਸ਼ਾਨਬੱਧ ਕਰਨ ਦਿਓ
• ਟਿੱਪਣੀ ਦਿਲ ਦਿਖਾਓ
-
ਸੁਧਾਰ
• ਮੈਟਾਡੇਟਾ ਅਤੇ ਟੈਗਸ ਲੇਆਉਟ ਵਿੱਚ ਸੁਧਾਰ ਕਰੋ
• UI ਭਾਗਾਂ 'ਤੇ ਸੇਵਾ ਰੰਗ ਲਾਗੂ ਕਰੋ
ਠੀਕ ਕੀਤਾ
• ਮਿੰਨੀ ਪਲੇਅਰ ਵਿੱਚ ਥੰਬਨੇਲ ਠੀਕ ਕਰੋ
• ਡੁਪਲੀਕੇਟ ਕਤਾਰ ਆਈਟਮਾਂ 'ਤੇ ਬੇਅੰਤ ਬਫਰਿੰਗ ਨੂੰ ਠੀਕ ਕਰੋ
-• ਕੁਝ ਪਲੇਅਰ ਫਿਕਸ ਜਿਵੇਂ ਰੋਟੇਸ਼ਨ ਅਤੇ ਤੇਜ਼ੀ ਨਾਲ ਬੰਦ ਹੋਣਾ
-• ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਲੋਡ ਕੀਤੇ ਬਾਕੀ ਬਚੇ ReCAPTCHA ਨੂੰ ਠੀਕ ਕਰੋ
-• ਫੀਡ ਨੂੰ ਤਾਜ਼ਾ ਕਰਨ ਵੇਲੇ ਕਲਿੱਕਾਂ ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਓ
+• ਕੁਝ ਪਲੇਅਰ ਫਿਕਸ
• ਕੁਝ ਡਾਊਨਲੋਡਰ ਕਰੈਸ਼ਾਂ ਨੂੰ ਠੀਕ ਕਰੋ
diff --git a/fastlane/metadata/android/pa/changelogs/976.txt b/fastlane/metadata/android/pa/changelogs/976.txt
index a1a1354ca..1f2a70887 100644
--- a/fastlane/metadata/android/pa/changelogs/976.txt
+++ b/fastlane/metadata/android/pa/changelogs/976.txt
@@ -1,10 +1 @@
-• ਪੂਰੀ ਸਕ੍ਰੀਨ ਵਿੱਚ ਪਲੇਅਰ ਨੂੰ ਸਿੱਧਾ ਖੋਲ੍ਹਣ ਲਈ ਵਿਕਲਪ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ
-• ਇਹ ਚੁਣਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ ਕਿ ਕਿਸ ਕਿਸਮ ਦੇ ਖੋਜ ਸੁਝਾਅ ਦਿਖਾਉਣੇ ਹਨ
-• ਗੂੜ੍ਹਾ ਥੀਮ ਹੁਣ ਗਹਿਰਾ ਗੂੜ੍ਹਾ + ਗੂੜ੍ਹਾ ਸਪਲੈਸ਼ ਸਕ੍ਰੀਨ ਜੋੜਿਆ ਗਿਆ ਹੈ
-• ਅਣਚਾਹੀਆਂ ਫ਼ਾਈਲਾਂ ਨੂੰ ਸਲੇਟੀ ਕਰਨ ਲਈ ਬਿਹਤਰ ਫ਼ਾਈਲ ਚੋਣਕਾਰ
-• ਸਥਿਰ YouTube ਗਾਹਕੀ ਆਯਾਤ
-
-• ਇੱਕ ਸਟ੍ਰੀਮ ਨੂੰ ਮੁੜ ਚਲਾਉਣ ਲਈ ਮੁੜ-ਪਲੇਅ ਬਟਨ 'ਤੇ ਟੈਪ ਕਰਨ ਦੀ ਲੋੜ ਹੈ
-• ਸਥਿਰ ਸਮਾਪਤੀ ਆਡੀਓ ਸੈਸ਼ਨ
-• [Android TV] DPad ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਸਮੇਂ ਸਥਿਰ ਲੰਬੀ ਸੀਕਬਾਰ ਜੰਪ
-ਹੋਰ ਤਬਦੀਲੀਆਂ ਦੇਖਣ ਲਈ, ਹੇਠਾਂ ਦਿੱਤੇ ਲਿੰਕ ਟੈਬ ਤੋਂ ਚੇਂਜਲੌਗ (ਅਤੇ ਬਲੌਗ ਪੋਸਟ) ਦੇਖੋ।
+• ਪੂਰੀ ਸਕ੍ਰੀਨ ਵਿੱਚ ਪਲੇਅਰ ਨੂੰ ਸਿੱਧਾ ਖੋਲ੍ਹਣ ਲਈ ਵਿਕਲਪ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ • ਇਹ ਚੁਣਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ ਕਿ ਕਿਸ ਕਿਸਮ ਦੇ ਖੋਜ ਸੁਝਾਅ ਦਿਖਾਉਣੇ ਹਨ • ਗੂੜ੍ਹਾ ਥੀਮ ਹੁਣ ਗੂੜ੍ਹਾ + ਗੂੜ੍ਹਾ ਸਪਲੈਸ਼ ਸਕ੍ਰੀਨ ਜੋੜਿਆ ਗਿਆ ਹੈ • ਅਣਚਾਹੀਆਂ ਫ਼ਾਈਲਾਂ ਨੂੰ ਸਲੇਟੀ ਕਰਨ ਲਈ ਬਿਹਤਰ ਫ਼ਾਈਲ ਚੋਣਕਾਰ • ਸਥਿਰ YouTube ਗਾਹਕੀ ਆਯਾਤ • ਇੱਕ ਸਟ੍ਰੀਮ ਨੂੰ ਮੁੜ ਚਲਾਉਣ ਲਈ ਮੁੜ-ਪਲੇਅ ਬਟਨ 'ਤੇ ਟੈਪ ਕਰਨ ਦੀ ਲੋੜ ਹੈ • ਸਥਿਰ ਸਮਾਪਤੀ ਆਡੀਓ ਸੈਸ਼ਨ • [Android TV] DPad ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਸਮੇਂ ਸਥਿਰ ਲੰਬੀ ਸੀਕਬਾਰ ਜੰਪ ਹੋਰ ਤਬਦੀਲੀਆਂ ਦੇਖਣ ਲਈ, ਹੇਠਾਂ ਦਿੱਤੇ ਲਿੰਕ ਟੈਬ ਤੋਂ ਚੇਂਜਲੌਗ (ਅਤੇ ਬਲੌਗ ਪੋਸਟ) ਦੇਖੋ।
diff --git a/fastlane/metadata/android/pa/changelogs/986.txt b/fastlane/metadata/android/pa/changelogs/986.txt
index b072d6cb9..3766ca8d1 100644
--- a/fastlane/metadata/android/pa/changelogs/986.txt
+++ b/fastlane/metadata/android/pa/changelogs/986.txt
@@ -1,15 +1,15 @@
ਨਵਾਂ
-• ਨਵੀਆਂ ਸਟ੍ਰੀਮਾਂ ਲਈ ਸੂਚਨਾਵਾਂ
-• ਬੈਕਗ੍ਰਾਊਂਡ ਅਤੇ ਵੀਡੀਓ ਪਲੇਅਰਾਂ ਵਿਚਕਾਰ ਅਰਾਮ ਨਾਲ ਤਬਦੀਲੀ
-• ਸੈਮੀਟੋਨਸ ਦੁਆਰਾ ਪਿੱਚ ਬਦਲੋ
-• ਇੱਕ ਪਲੇਲਿਸਟ ਵਿੱਚ ਮੁੱਖ ਪਲੇਅਰ ਕਤਾਰ ਜੋੜੋ
+• ਨਵੀਆਂ ਸਟ੍ਰੀਮਾਂ ਲਈ ਸੂਚਨਾਵਾਂ
+• ਬੈਕਗ੍ਰਾਊਂਡ ਅਤੇ ਵੀਡੀਓ ਪਲੇਅਰਾਂ ਵਿਚਕਾਰ ਅਰਾਮ ਨਾਲ ਤਬਦੀਲੀ
+• ਸੈਮੀਟੋਨਸ ਦੁਆਰਾ ਪਿੱਚ ਬਦਲੋ
+• ਇੱਕ ਪਲੇਲਿਸਟ ਵਿੱਚ ਮੁੱਖ ਪਲੇਅਰ ਕਤਾਰ ਜੋੜੋ
ਸੁਧਾਰ
-• ਸਪੀਡ/ਪਿਚ ਸਟੈਪ ਦਾ ਆਕਾਰ ਯਾਦ ਰੱਖੋ
-• ਵੀਡੀਓ ਪਲੇਅਰ ਵਿੱਚ ਸ਼ੁਰੂਆਤੀ ਲੰਬੇ ਬਫਰਿੰਗ ਨੂੰ ਘੱਟ ਕਰੋ • Android TV ਲਈ ਪਲੇਅਰ UI ਵਿੱਚ ਸੁਧਾਰ ਕਰੋ
+• ਸਪੀਡ/ਪਿਚ ਸਟੈਪ ਦਾ ਆਕਾਰ ਯਾਦ ਰੱਖੋ
+• ਵੀਡੀਓ ਪਲੇਅਰ ਵਿੱਚ ਸ਼ੁਰੂਆਤੀ ਲੰਬੇ ਬਫਰਿੰਗ ਨੂੰ ਘੱਟ ਕਰੋ
+• Android TV ਲਈ ਪਲੇਅਰ UI ਵਿੱਚ ਸੁਧਾਰ ਕਰੋ
• ਸਾਰੀਆਂ ਡਾਊਨਲੋਡ ਕੀਤੀਆਂ ਫ਼ਾਈਲਾਂ ਨੂੰ ਮਿਟਾਉਣ ਤੋਂ ਪਹਿਲਾਂ ਪੁਸ਼ਟੀ ਕਰੋ
-ਠੀਕ ਕੀਤਾ
-• ਮੀਡੀਆ ਬਟਨ ਨੂੰ ਫਿਕਸ ਕਰੋ ਜੋ ਪਲੇਅਰ ਨਿਯੰਤਰਣਾਂ ਨੂੰ ਨਹੀਂ ਲੁਕਾਉਂਦਾ ਹੈ
+ਫਿਕਸਡ
+• ਮੀਡੀਆ ਬਟਨ ਨੂੰ ਫਿਕਸ ਕਰੋ ਜੋ ਪਲੇਅਰ ਨਿਯੰਤਰਣਾਂ ਨੂੰ ਨਹੀਂ ਲੁਕਾਉਂਦਾ ਹੈ
• ਪਲੇਅਰ ਦੀ ਕਿਸਮ ਬਦਲਣ 'ਤੇ ਪਲੇਬੈਕ ਰੀਸੈਟ ਨੂੰ ਠੀਕ ਕਰੋ
-• ਪਲੇਲਿਸਟ ਡਾਇਲਾਗ ਨੂੰ ਘੁੰਮਾਉਣ ਨੂੰ ਠੀਕ ਕਰੋ
diff --git a/fastlane/metadata/android/pa/changelogs/987.txt b/fastlane/metadata/android/pa/changelogs/987.txt
index 93fc77a77..52d0bb828 100644
--- a/fastlane/metadata/android/pa/changelogs/987.txt
+++ b/fastlane/metadata/android/pa/changelogs/987.txt
@@ -6,6 +6,4 @@
ਸੁਧਾਰ
• ਪਲੇਬੈਕ ਪੈਰਾਮੀਟਰ ਡਾਇਲਾਗ ਵਿੱਚ ਸੁਧਾਰ ਕਰੋ
• ਗਾਹਕੀ ਆਯਾਤ/ਨਿਰਯਾਤ ਬਟਨਾਂ ਨੂੰ ਤਿੰਨ-ਬਿੰਦੀਆਂ ਵਾਲੇ ਮੀਨੂ ਵਿੱਚ ਲੈ ਜਾਓ
-
-ਠੀਕ ਕੀਤਾ
-• ਪਲੇਲਿਸਟ ਤੋਂ ਪੂਰੀ ਤਰ੍ਹਾਂ ਦੇਖੇ ਗਏ ਵੀਡੀਓ ਨੂੰ ਹਟਾਉਣਾ ਠੀਕ ਕਰੋ • ਸ਼ੇਅਰ ਮੀਨੂ ਥੀਮ ਅਤੇ "ਪਲੇਲਿਸਟ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ" ਐਂਟਰੀ ਨੂੰ ਠੀਕ ਕਰੋ
+ਠੀਕ ਕੀਤਾ
diff --git a/fastlane/metadata/android/pa/changelogs/990.txt b/fastlane/metadata/android/pa/changelogs/990.txt
index bd532ecb0..90cd8b35c 100644
--- a/fastlane/metadata/android/pa/changelogs/990.txt
+++ b/fastlane/metadata/android/pa/changelogs/990.txt
@@ -1,13 +1,10 @@
-ਇਹ ਰੀਲੀਜ਼ Android 4.4 ਕਿਟਕੈਟ ਲਈ ਸਮਰਥਨ ਛੱਡਦੀ ਹੈ, ਹੁਣ ਘੱਟੋ-ਘੱਟ ਸੰਸਕਰਣ Android 5 Lollipop ਹੈ!
-ਨਵਾਂ
-• ਲੰਬੇ ਸਮੇਂ ਤੱਕ ਦਬਾਉਣ ਵਾਲੇ ਮੀਨੂ ਤੋਂ ਡਾਊਨਲੋਡ ਕਰੋ
-• ਫੀਡ ਵਿੱਚ ਭਵਿੱਖ ਦੇ ਵੀਡੀਓ ਲੁਕਾਓ
-• ਸਥਾਨਕ ਪਲੇਲਿਸਟਾਂ ਨੂੰ ਸਾਂਝਾ ਕਰੋ
-ਸੁਧਾਰ
-• ਪਲੇਅਰ ਕੋਡ ਨੂੰ ਛੋਟੇ ਹਿੱਸਿਆਂ ਵਿੱਚ ਰੀਫੈਕਟਰ ਕਰੋ: ਘੱਟ RAM ਵਰਤੀ ਗਈ, ਘੱਟ ਬੱਗ
-• ਥੰਮਨੇਲ ਦੇ ਸਕੇਲ ਮੋਡ ਵਿੱਚ ਸੁਧਾਰ ਕਰੋ
-• ਚਿੱਤਰ ਪਲੇਸਹੋਲਡਰ ਨੂੰ ਵੈਕਟਰਾਈਜ਼ ਕਰੋ
-
-ਠੀਕ ਕੀਤਾ
-• ਪਲੇਅਰ ਨੋਟੀਫਿਕੇਸ਼ਨ ਨਾਲ ਵੱਖ-ਵੱਖ ਮੁੱਦਿਆਂ ਨੂੰ ਹੱਲ ਕਰੋ: ਪੁਰਾਣੀ/ਗੁੰਮ ਮੀਡੀਆ ਜਾਣਕਾਰੀ, ਵਿਗੜਿਆ ਥੰਮਨੇਲ
+ਇਹ ਰਿਲੀਜ਼ Android 4.4 ਕਿਟਕੈਟ ਲਈ ਸਮਰਥਨ ਛੱਡਦੀ ਹੈ, ਹੁਣ ਘੱਟੋ-ਘੱਟ ਸੰਸਕਰਣ Android 5 Lollipop ਹੈ!
+ਨਵਾਂ
+• ਲੰਬੇ ਸਮੇਂ ਤੱਕ ਦਬਾਉਣ ਵਾਲੇ ਮੀਨੂ ਤੋਂ ਡਾਊਨਲੋਡ ਕਰੋ
+• ਫੀਡ ਵਿੱਚ ਭਵਿੱਖ ਦੇ ਵੀਡੀਓ ਲੁਕਾਓ
+• ਸਥਾਨਕ ਪਲੇਲਿਸਟਾਂ ਨੂੰ ਸਾਂਝਾ ਕਰੋ
+ਸੁਧਾਰ
+• ਪਲੇਅਰ ਕੋਡ ਨੂੰ ਛੋਟੇ ਹਿੱਸਿਆਂ ਵਿੱਚ ਰੀਫੈਕਟਰ ਕਰੋ: ਘੱਟ RAM ਵਰਤੇਗੀ, ਘੱਟ ਬੱਗ ਹੋਣਗੇ
+
+ਠੀਕ ਕੀਤਾ
• ਪੂਰੀ ਸਕ੍ਰੀਨ ਦੀ ਥਾਂ ਉਸਦੇ 1/4 ਹਿੱਸੇ ਦੀ ਵਰਤੋਂ ਨੂੰ ਠੀਕ ਕਰੋ
diff --git a/fastlane/metadata/android/pa/changelogs/995.txt b/fastlane/metadata/android/pa/changelogs/995.txt
index 0da0a4261..dc9c576c9 100644
--- a/fastlane/metadata/android/pa/changelogs/995.txt
+++ b/fastlane/metadata/android/pa/changelogs/995.txt
@@ -5,12 +5,10 @@
ਸੁਧਾਰ
• ਪਲੇਅਰ ਇੰਟਰਫੇਸ ਦੀ ਪਹੁੰਚਯੋਗਤਾ
-• ਸਿਰਫ਼-ਵੀਡੀਓ ਡਾਊਨਲੋਡਾਂ ਲਈ ਬਿਹਤਰ ਆਡੀਓ ਚੋਣ
-• ਸਾਂਝੀ ਕੀਤੀ ਪਲੇਲਿਸਟ ਸਮੱਗਰੀ ਵਿੱਚ ਪਲੇਲਿਸਟ ਅਤੇ ਵੀਡੀਓ ਨਾਮ ਸ਼ਾਮਲ ਕਰਨ ਦਾ ਵਿਕਲਪ
+• ਪਲੇਲਿਸਟ ਸ਼ੇਅਰਿੰਗ ਸਮੱਗਰੀ ਵਿੱਚ ਪਲੇਲਿਸਟ ਨਾਮ ਅਤੇ ਵੀਡੀਓ ਨਾਮ ਜੋੜਨ ਲਈ ਵਿਕਲਪ
+• ਅੰਦਰੂਨੀ ਸੁਧਾਰ ਅਤੇ ਨਿਰਭਰਤਾ ਅੱਪਡੇਟ
ਠੀਕ ਕੀਤੇ
-• [ਯੂਟਿਊਬ] ਲਾਈਕ ਗਿਣਤੀ ਨੂੰ ਠੀਕ ਕਰੋ
-• ਪਲੇਅਰ ਰਿਸਪੌੰਡ ਨਹੀਂ ਕਰ ਰਿਹਾ ਦੇ ਸੁਨੇਹੇ ਦੇਣ ਵਾਲੇ ਪੌਪਅੱਪ ਅਤੇ ਕਰੈਸ਼ਾਂ ਨੂੰ ਠੀਕ ਕਰੋ
• ਭਾਸ਼ਾ ਚੋਣਕਾਰ ਵਿੱਚ ਗਲਤ ਭਾਸ਼ਾਵਾਂ ਦੀ ਚੋਣ
• ਪਲੇਅਰ ਆਡੀਓ ਫੋਕਸ ਮਿਊਟ ਦਾ ਆਦਰ ਨਹੀਂ ਕਰ ਰਿਹਾ ਸੀ
-• ਪਲੇਲਿਸਟਾਂ ਵਿੱਚ ਆਈਟਮਾਂ ਨੂੰ ਜੋੜਨਾ ਕਦੇ-ਕਦਾਈਂ ਕੰਮ ਨਹੀਂ ਕਰ ਰਿਹਾ ਸੀ
+• ਖਾਸ ਮਾਮਲਿਆਂ ਵਿੱਚ ਪਲੇਲਿਸਟਾਂ ਵਿੱਚ ਆਈਟਮਾਂ ਨੂੰ ਜੋੜਨਾ ਕੰਮ ਨਹੀਂ ਕਰ ਰਿਹਾ ਸੀ
diff --git a/fastlane/metadata/android/pa/changelogs/997.txt b/fastlane/metadata/android/pa/changelogs/997.txt
index 8e0cb85f2..a33ff32af 100644
--- a/fastlane/metadata/android/pa/changelogs/997.txt
+++ b/fastlane/metadata/android/pa/changelogs/997.txt
@@ -12,6 +12,4 @@
ਠੀਕ ਕੀਤਾ
• [ਯੂਟਿਊਬ] ਲੋਡ ਨਾ ਹੋਣ ਵਾਲੀਆਂ ਟਿੱਪਣੀਆਂ ਨੂੰ ਠੀਕ ਕਰੋ, ਨਾਲ ਹੀ ਹੋਰ ਫਿਕਸ ਅਤੇ ਸੁਧਾਰ
-• ਸੈਟਿੰਗਾਂ ਆਯਾਤ ਕਰਨ ਵਿੱਚ ਕਮਜ਼ੋਰੀ ਨੂੰ ਹੱਲ ਕਰੋ ਅਤੇ JSON 'ਤੇ ਸਵਿੱਚ ਕਰੋ
• ਕਈ ਡਾਊਨਲੋਡ ਫਿਕਸ
-• ਖੋਜ ਟੈਕਸਟ ਨੂੰ ਟਰਿੱਮ ਕਰੋ
diff --git a/fastlane/metadata/android/pl/changelogs/1006.txt b/fastlane/metadata/android/pl/changelogs/1006.txt
new file mode 100644
index 000000000..a537d7c18
--- /dev/null
+++ b/fastlane/metadata/android/pl/changelogs/1006.txt
@@ -0,0 +1,16 @@
+Ulepszone
+- Utrzymyw. bieżącego odtwarzacza przy naciskaniu znaczników czasu
+- Próba odzysk. oczekuj. pobierań, jeśli to możliwe
+- Dodano opcję usuwania pobierania bez usuwania pliku
+- Uprawnienie na nakładkę: wyświetl. okna z objaśnieniami dla Androida powyżej R
+- Obsługa otw. linków on.soundcloud
+- Wiele drobnych ulepszeń i optymal.
+
+Naprawione
+- Formatow. krótkich liczb na Androidzie poniżej 7
+- Puste powiadomienia
+- Pliki napisów SRT
+- Mnóstwo awarii
+
+Rozwój
+- Modernizacja wewnętrznego kodu
diff --git a/fastlane/metadata/android/pt-BR/changelogs/1005.txt b/fastlane/metadata/android/pt-BR/changelogs/1005.txt
new file mode 100644
index 000000000..3ef1f3e2e
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/1005.txt
@@ -0,0 +1,17 @@
+New
+• Suporte adicionado para Android Auto
+• Permitir configuração de grupos de feed como abas da tela principal
+• [YouTube] Compartilhe como playlist temporária
+• [SoundCloud] Aba de curtidas do canal
+
+Melhorado
+• Melhor sugestão na barra de busca
+• Mostra data do download em Downloads
+• Usar idioma por aplicativo no Android 13
+
+Consertado
+• Texto no modo escuro consertado
+• [YouTube] Conserta playlists não carregando mais do que 100 itens
+• [YouTube] Conserta videos recomendados faltando
+• Conserta lista de visualização do histórico
+• Conserta registro de tempo na resposta de comentários
diff --git a/fastlane/metadata/android/pt-BR/changelogs/966.txt b/fastlane/metadata/android/pt-BR/changelogs/966.txt
new file mode 100644
index 000000000..13722dc34
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/966.txt
@@ -0,0 +1,14 @@
+Novo:
+- Acrescentado um novo serviço: Bandcamp
+
+Melhorado:
+- Adicionada uma opção para que a aplicação siga o tema do dispositivo
+- Previne alguns travamentos mostrando um painel de erros melhorado
+- Mostra mais informações sobre as causas da indisponibilidade do conteúdo
+- A tecla de espaço de hardware ativa play/pausa
+- Mostra "Download iniciado"
+
+Resolvido:
+- Miniaturas muito pequenas em detalhes de vídeo enquanto se reproduz em fundo
+- Corrige título vazio em tocador minimizado
+- O último modo de redimensionamento do tamanho não estava sendo restaurado corretamente
diff --git a/fastlane/metadata/android/pt-BR/changelogs/967.txt b/fastlane/metadata/android/pt-BR/changelogs/967.txt
new file mode 100644
index 000000000..96ce3c07f
--- /dev/null
+++ b/fastlane/metadata/android/pt-BR/changelogs/967.txt
@@ -0,0 +1 @@
+Corrigido o YouTube que não funcionava corretamente na UE. Foi causado por um novo cookie e sistema de consentimento de privacidade que requer que a NewPipe configure um cookie CONSENT.
diff --git a/fastlane/metadata/android/pt-PT/changelogs/1005.txt b/fastlane/metadata/android/pt-PT/changelogs/1005.txt
new file mode 100644
index 000000000..ea0f44608
--- /dev/null
+++ b/fastlane/metadata/android/pt-PT/changelogs/1005.txt
@@ -0,0 +1,15 @@
+Novo
+• Adicionado apoio para Android Auto
+• Permite definir grupos de feeds como guias do ecrã principal
+• [YouTube] Partilhar como lista de reprodução temporária
+• [SoundCloud] Separador de gostos do canal
+
+Melhorado
+• Melhores sugestões na barra de pesquisa
+• Mostrar data da descarga em descargas
+• Usar idioma por app do Android 13
+
+Corrigido
+• Corrigir cores de texto incorretas no modo escuro
+• [YouTube] Corrigir listas de reprodução que não carregam mais de 100 elementos
+...
diff --git a/fastlane/metadata/android/pt/changelogs/1005.txt b/fastlane/metadata/android/pt/changelogs/1005.txt
new file mode 100644
index 000000000..ea0f44608
--- /dev/null
+++ b/fastlane/metadata/android/pt/changelogs/1005.txt
@@ -0,0 +1,15 @@
+Novo
+• Adicionado apoio para Android Auto
+• Permite definir grupos de feeds como guias do ecrã principal
+• [YouTube] Partilhar como lista de reprodução temporária
+• [SoundCloud] Separador de gostos do canal
+
+Melhorado
+• Melhores sugestões na barra de pesquisa
+• Mostrar data da descarga em descargas
+• Usar idioma por app do Android 13
+
+Corrigido
+• Corrigir cores de texto incorretas no modo escuro
+• [YouTube] Corrigir listas de reprodução que não carregam mais de 100 elementos
+...
diff --git a/fastlane/metadata/android/ru/changelogs/1000.txt b/fastlane/metadata/android/ru/changelogs/1000.txt
index 90c03f3cf..776041988 100644
--- a/fastlane/metadata/android/ru/changelogs/1000.txt
+++ b/fastlane/metadata/android/ru/changelogs/1000.txt
@@ -10,4 +10,4 @@
• Исправить выход из диалогового окна загрузки до его появления.
• Исправить всплывающее окно с списком связанных элементов.
• Исправлена последовательность в диалоговом окне добавления в плейлист.
-• Настроена компоновка элементов закладок плейлиста.
+• Настроена компоновка элементов закладок плейлиста
diff --git a/fastlane/metadata/android/ru/changelogs/1001.txt b/fastlane/metadata/android/ru/changelogs/1001.txt
index 11c3a1061..7b9f2be2f 100644
--- a/fastlane/metadata/android/ru/changelogs/1001.txt
+++ b/fastlane/metadata/android/ru/changelogs/1001.txt
@@ -1,10 +1,6 @@
Улучшенный
-
-- Всегда можно изменить настройки уведомлений игрока на Android 13+
-
+• Всегда можно изменить настройки уведомлений игрока на Android 13+
Исправлено
-
-- Исправление экспорта базы данных/подписок, который не обрезал уже существующий файл, что могло привести к повреждению экспорта
-
-- Исправлено возобновление работы плеера с самого начала при нажатии на временную метку
+• Исправление экспорта базы данных/подписок, который не обрезал уже существующий файл, что могло привести к повреждению экспорта
+• Исправлено возобновление работы плеера с самого начала при нажатии на временную метку
diff --git a/fastlane/metadata/android/ru/changelogs/1002.txt b/fastlane/metadata/android/ru/changelogs/1002.txt
index d3978869d..efa895dbf 100644
--- a/fastlane/metadata/android/ru/changelogs/1002.txt
+++ b/fastlane/metadata/android/ru/changelogs/1002.txt
@@ -1 +1,4 @@
-Исправлено: YouTube не воспроизводил никакие потоки
+Исправлена ошибка, из-за которой YouTube не воспроизводил ни одного потока.
+
+В этом выпуске исправлена только самая серьёзная ошибка, препятствующая загрузке информации о видео YouTube.
+Мы знаем о существовании других проблем и вскоре выпустим отдельный выпуск для их решения.
diff --git a/fastlane/metadata/android/ru/changelogs/1003.txt b/fastlane/metadata/android/ru/changelogs/1003.txt
index d3978869d..4b8843d5c 100644
--- a/fastlane/metadata/android/ru/changelogs/1003.txt
+++ b/fastlane/metadata/android/ru/changelogs/1003.txt
@@ -1 +1,6 @@
-Исправлено: YouTube не воспроизводил никакие потоки
+Это релиз исправления, исправляющий ошибки YouTube:
+• [YouTube] Исправлена проблема с загрузкой видеоинформации, исправлены ошибки HTTP 403 при воспроизведении видео и восстановлено воспроизведение некоторых видео с возрастными ограничениями
+• Исправлена проблема с отсутствием изменения размера субтитров
+• Исправлена проблема с двойной загрузкой информации при открытии трансляции
+• [Soundcloud] Удалены невоспроизводимые трансляции с защитой DRM
+• Обновлены переводы
diff --git a/fastlane/metadata/android/ru/changelogs/1004.txt b/fastlane/metadata/android/ru/changelogs/1004.txt
index d3978869d..e6bef35b9 100644
--- a/fastlane/metadata/android/ru/changelogs/1004.txt
+++ b/fastlane/metadata/android/ru/changelogs/1004.txt
@@ -1 +1,3 @@
-Исправлено: YouTube не воспроизводил никакие потоки
+В этом выпуске YouTube теперь поддерживает только трансляцию в формате 360p.
+
+Обратите внимание, что решение, используемое в этой версии, вероятно, временное, и в долгосрочной перспективе потребуется внедрение видеопротокола SABR. Участники TeamNewPipe сейчас заняты, поэтому любая помощь будет высоко оценена! https://github.com/TeamNewPipe/NewPipe/issues/12248
diff --git a/fastlane/metadata/android/ru/changelogs/930.txt b/fastlane/metadata/android/ru/changelogs/930.txt
index 58a849bf4..0ad761f55 100644
--- a/fastlane/metadata/android/ru/changelogs/930.txt
+++ b/fastlane/metadata/android/ru/changelogs/930.txt
@@ -7,7 +7,7 @@
• Показывать сообщение, когда контент еще не поддерживается, вместо сбоя
• Улучшено изменение размера всплывающего проигрывателя с помощью пинч-жестов
• Постановка потоков в очередь при длительном нажатии на фоновые и всплывающие кнопки в канале
-• Улучшена обработка размера заголовка заголовка ящика
+• Улучшена обработка размера заголовка
Исправления
• Исправлена ошибка, из-за которой не работает настройка контента с ограничением по возрасту
diff --git a/fastlane/metadata/android/ru/changelogs/999.txt b/fastlane/metadata/android/ru/changelogs/999.txt
index d3978869d..bf6e1c375 100644
--- a/fastlane/metadata/android/ru/changelogs/999.txt
+++ b/fastlane/metadata/android/ru/changelogs/999.txt
@@ -1 +1,12 @@
-Исправлено: YouTube не воспроизводил никакие потоки
+Этот выпуск исправления исправляет ошибки HTTP 403 в середине видео на YouTube.
+
+Новое
+• [SoundCloud] Добавлена поддержка URL-адресов on.soundcloud.com
+
+Улучшено
+• [Bandcamp] Отображение дополнительной информации в радиокиоске
+
+Исправлено
+• [YouTube] Исправлены случайные ошибки HTTP 403 в начале или середине видео
+• [YouTube] Извлечение аватара и баннера из большего количества типов заголовков каналов
+• [Bandcamp] Исправлены различные ошибки и всегда используется HTTPS
diff --git a/fastlane/metadata/android/sat/short_description.txt b/fastlane/metadata/android/sat/short_description.txt
new file mode 100644
index 000000000..9e7874738
--- /dev/null
+++ b/fastlane/metadata/android/sat/short_description.txt
@@ -0,0 +1 @@
+ᱮᱱᱰᱨᱳᱭᱮᱰ ᱞᱟᱹᱜᱤᱫ ᱢᱤᱫ ᱯᱷᱨᱤ ᱦᱟᱞᱠᱟ ᱚᱡᱚᱱ ᱭᱩᱴᱭᱩᱵᱽ ᱯᱷᱨᱚᱱᱴᱮᱱᱰ ᱾
diff --git a/fastlane/metadata/android/sk/changelogs/1005.txt b/fastlane/metadata/android/sk/changelogs/1005.txt
index 8f2bfbfab..2bfdfca0e 100644
--- a/fastlane/metadata/android/sk/changelogs/1005.txt
+++ b/fastlane/metadata/android/sk/changelogs/1005.txt
@@ -1,18 +1,17 @@
-Novinky
-• Pridaná podpora pre Android Auto
-• Možnosť nastaviť skupiny kanálov ako hlavné karty na obrazovke
-• [YouTube] Zdieľanie ako dočasný playlist
+New
+• Add support for Android Auto
+• Allow setting feed groups as main screen tabs
+• [YouTube] Share as temporary playlist
+• [SoundCloud] Likes channel tab
-• [SoundCloud] Karta „Páči sa“ kanál.
+Improved
+• Better search bar hints
+• Show download date in Downloads
+• Use Android 13 per-app language
-Vylepšenia
-• Lepšia nápoveda v paneli vyhľadávania
-• Zobrazenie dátumu stiahnutia v sekcii „Stiahnuté”
-• Použitie jazyka Android 13 pre jednotlivé aplikácie
-
-Opravy
-• Oprava chybných farieb textu v tmavom režime
-• [YouTube] Oprava playlistov, ktoré nenačítavajú viac ako 100 položiek
-• [YouTube] Oprava chýbajúcich odporúčaných videí
-• Oprava pádov v zobrazení zoznamu histórie
-• Oprava časových značiek v odpovediach na komentáre.
+Fixed
+• Fix broken text colors in dark mode
+• [YouTube] Fix playlists not loading more than 100 items
+• [YouTube] Fix missing recommended videos
+• Fix crashes in History list view
+• Fix timestamps in comment replies
diff --git a/fastlane/metadata/android/sk/changelogs/1006.txt b/fastlane/metadata/android/sk/changelogs/1006.txt
new file mode 100644
index 000000000..6bc6f9a2b
--- /dev/null
+++ b/fastlane/metadata/android/sk/changelogs/1006.txt
@@ -0,0 +1,16 @@
+# Improved
+Keep current player when clicking on timestamps
+Try to recover pending download missions when possible
+Add option to delete a download without also deleting file
+Overlay Permission: display explanatory dialog for Android > R
+Support on.soundcloud link opening
+A lot of small improvements and optimizations
+
+# Fixed
+Fix short count formatting for Android versions below 7
+Fix ghost notifications
+Fixes for SRT subtitle files
+Fixed tons of crashes
+
+# Development
+Internal code modernization
diff --git a/fastlane/metadata/android/sk/changelogs/65.txt b/fastlane/metadata/android/sk/changelogs/65.txt
index c7cac2626..8570a056a 100644
--- a/fastlane/metadata/android/sk/changelogs/65.txt
+++ b/fastlane/metadata/android/sk/changelogs/65.txt
@@ -1,26 +1,26 @@
-### Zlepšenia
+### Improvements
-- Zakázanie animácie ikony burgermenu #1486
-- Zrušenie odstránenia stiahnutých súborov #1472
-- Možnosť sťahovania v ponuke zdieľania #1498
-- Pridaná možnosť zdieľania do ponuky dlhého ťuknutia #1454
-- Minimalizácia hlavného prehrávača pri ukončení #1354
-- Aktualizácia verzie knižnice a oprava zálohovania databázy #1510
-- Aktualizácia ExoPlayer 2.8.2 #1392
- - Prepracované dialógové okno na ovládanie rýchlosti prehrávania tak, aby podporovalo rôzne veľkosti krokov pre rýchlejšiu zmenu rýchlosti.
- - Pridaný prepínač na rýchle prevíjanie dopredu počas ticha v ovládaní rýchlosti prehrávania. Toto by malo byť užitočné pre audioknihy a niektoré hudobné žánre a môže priniesť skutočne plynulý zážitok (a môže prerušiť skladbu s množstvom ticha =\).
- - Prepracované rozlíšenie zdrojov médií, aby bolo možné odovzdávať metadáta spolu s médiami interne v prehrávači, namiesto toho, aby sa to robilo ručne. Teraz máme jediný zdroj metadát a je priamo k dispozícii pri spustení prehrávania.
- - Opravené neaktualizovanie metadát vzdialeného zoznamu skladieb, keď sú k dispozícii nové metadáta pri otvorení fragmentu zoznamu skladieb.
- - Rôzne opravy používateľského rozhrania: #1383, ovládacie prvky oznámenia prehrávača na pozadí sú teraz vždy biele, jednoduchšie vypnutie vyskakovacieho prehrávača prostredníctvom hodenia
-- Použitie nového extraktora s preformulovanou architektúrou pre multiservis
+- Disable burgermenu icon animation #1486
+- undo delete of downloads #1472
+- Download option in share menu #1498
+- Added share option to long tap menu #1454
+- Minimize main player on exit #1354
+- Library version update and database backup fix #1510
+- ExoPlayer 2.8.2 Update #1392
+ - Reworked the playback speed control dialog to support different step sizes for faster speed change.
+ - Added a toggle to fast-forward during silences in playback speed control. This should be helpful for audiobooks and certain music genres, and can bring a true seamless experience (and can break a song with lots of silences =\\).
+ - Refactored media source resolution to allow passing metadata alongside media internally in the player, rather than doing so manually. Now we have a single source of metadata and is directly available when playback starts.
+ - Fixed remote playlist metadata not updating when new metadata is available when playlist fragment is opened.
+ - Various UI fixes: #1383, background player notification controls now always white, easier to shutdown popup player through flinging
+- Use new extractor with refactored architecture for multiservice
-### Opravy
+### Fixes
-- Oprava #1440 Nefunkčné rozloženie informácií o videu #1491
-- Oprava histórie zobrazenia #1497
- - #1495 aktualizáciou metadát (miniatúry, názov a počet videí) hneď, ako používateľ vstúpi do zoznamu skladieb.
- - #1475, zaregistrovaním zobrazenia v databáze, keď používateľ spustí video v externom prehrávači na detailnom fragmente.
-- Oprava časového limitu creen v prípade popup režimu. #1463 (Opravené #640)
-- Oprava hlavného prehrávača videa č. 1509
- - #1412] Opravený režim opakovania spôsobujúci NPE prehrávača, keď je prijatý nový zámer, zatiaľ čo je činnosť prehrávača na pozadí.
- - Opravené minimalizovanie prehrávača na vyskakovacie okno nezničí prehrávač, keď nie je udelené povolenie na vyskakovanie.
+- Fix #1440 Broken Video Info Layout #1491
+- View history fix #1497
+ - #1495, by updating the metadata (thumbnail, title and video count) as soon as the user access the playlist.
+ - #1475, by registering a view in the database when the user starts a video on external player on detail fragment.
+- Fix creen timeout in case of popup mode. #1463 (Fixed #640)
+- Main video player fix #1509
+ - [#1412] Fixed repeat mode causing player NPE when new intent is received while player activity is in background.
+ - Fixed minimizing player to popup does not destroy player when popup permission is not granted.
diff --git a/fastlane/metadata/android/sk/changelogs/66.txt b/fastlane/metadata/android/sk/changelogs/66.txt
index ba9808cba..30c20b0e8 100644
--- a/fastlane/metadata/android/sk/changelogs/66.txt
+++ b/fastlane/metadata/android/sk/changelogs/66.txt
@@ -1,33 +1,33 @@
-# Zoznam zmien verzie v0.13.7
+# Changelog of v0.13.7
-### Opravené
-- Oprava problémov s triediacim filtrom vo verzii v0.13.6
+### Fixed
+- Fix sort filter issues of v0.13.6
-# Zoznam zmien verzie v0.13.6
+# Changelog of v0.13.6
-### Vylepšenia
+### Improvements
-- Zakázanie animácie ikony burgermenu #1486
-- Zrušenie odstránenia stiahnutých súborov #1472
-- Možnosť sťahovania v ponuke zdieľania #1498
-- Pridaná možnosť zdieľania do ponuky dlhého ťuknutia #1454
-- Minimalizácia hlavného prehrávača pri ukončení #1354
-- Aktualizácia verzie knižnice a oprava zálohovania databázy #1510
-- Aktualizácia ExoPlayer 2.8.2 #1392
- - Prepracované dialógové okno na ovládanie rýchlosti prehrávania tak, aby podporovalo rôzne veľkosti krokov pre rýchlejšiu zmenu rýchlosti.
- - Pridaný prepínač na rýchle prevíjanie dopredu počas ticha v ovládaní rýchlosti prehrávania. Toto by malo byť užitočné pre audioknihy a niektoré hudobné žánre a môže priniesť skutočne plynulý zážitok (a môže prerušiť skladbu s množstvom ticha =\).
- - Prepracované rozlíšenie zdrojov médií, aby bolo možné odovzdávať metadáta spolu s médiami interne v prehrávači, namiesto toho, aby sa to robilo ručne. Teraz máme jediný zdroj metadát a je priamo k dispozícii pri spustení prehrávania.
- - Opravené neaktualizovanie metadát vzdialeného zoznamu skladieb, keď sú k dispozícii nové metadáta pri otvorení fragmentu zoznamu skladieb.
- - Rôzne opravy používateľského rozhrania: #1383, ovládacie prvky oznámenia prehrávača na pozadí sú teraz vždy biele, jednoduchšie vypnutie vyskakovacieho prehrávača prostredníctvom hodenia
-- Použitie nového extraktora s preformulovanou architektúrou pre multiservis
+- Disable burgermenu icon animation #1486
+- undo delete of downloads #1472
+- Download option in share menu #1498
+- Added share option to long tap menu #1454
+- Minimize main player on exit #1354
+- Library version update and database backup fix #1510
+- ExoPlayer 2.8.2 Update #1392
+ - Reworked the playback speed control dialog to support different step sizes for faster speed change.
+ - Added a toggle to fast-forward during silences in playback speed control. This should be helpful for audiobooks and certain music genres, and can bring a true seamless experience (and can break a song with lots of silences =\\).
+ - Refactored media source resolution to allow passing metadata alongside media internally in the player, rather than doing so manually. Now we have a single source of metadata and is directly available when playback starts.
+ - Fixed remote playlist metadata not updating when new metadata is available when playlist fragment is opened.
+ - Various UI fixes: #1383, background player notification controls now always white, easier to shutdown popup player through flinging
+- Use new extractor with refactored architecture for multiservice
-### Opravy
+### Fixes
-- Oprava #1440 Nefunkčné rozloženie informácií o videu #1491
-- Oprava histórie zobrazenia #1497
- - #1495 aktualizáciou metadát (miniatúry, názov a počet videí) hneď, ako používateľ vstúpi do zoznamu skladieb.
- - #1475, zaregistrovaním zobrazenia v databáze, keď používateľ spustí video v externom prehrávači na detailnom fragmente.
-- Oprava časového limitu creen v prípade popup režimu. #1463 (Opravené #640)
-- Oprava hlavného prehrávača videa č. 1509
- - #1412] Opravený režim opakovania spôsobujúci NPE prehrávača, keď je prijatý nový zámer, zatiaľ čo je činnosť prehrávača na pozadí.
- - Opravené minimalizovanie prehrávača na vyskakovacie okno nezničí prehrávač, keď nie je udelené povolenie na vyskakovanie.
+- Fix #1440 Broken Video Info Layout #1491
+- View history fix #1497
+ - #1495, by updating the metadata (thumbnail, title and video count) as soon as the user access the playlist.
+ - #1475, by registering a view in the database when the user starts a video on external player on detail fragment.
+- Fix creen timeout in case of popup mode. #1463 (Fixed #640)
+- Main video player fix #1509
+ - [#1412] Fixed repeat mode causing player NPE when new intent is received while player activity is in background.
+ - Fixed minimizing player to popup does not destroy player when popup permission is not granted.
diff --git a/fastlane/metadata/android/sr/changelogs/994.txt b/fastlane/metadata/android/sr/changelogs/994.txt
index 3ed14410d..4fa4f102b 100644
--- a/fastlane/metadata/android/sr/changelogs/994.txt
+++ b/fastlane/metadata/android/sr/changelogs/994.txt
@@ -7,7 +7,7 @@
• [Bandcamp] Управљање нумерама иза платног зида
Поправљено
-• [YouTube] 403 HTTP грешке за стримове
+• [YouTube] 403 HTTP грешке за токове
• Црни плејер при преласку на главни плејер са приказа плејлисте
• Цурење сервисне меморије плејера
• [PeerTube] Аватари отпремаоца и подканала су замењени
diff --git a/fastlane/metadata/android/sv/changelogs/1005.txt b/fastlane/metadata/android/sv/changelogs/1005.txt
new file mode 100644
index 000000000..203cac267
--- /dev/null
+++ b/fastlane/metadata/android/sv/changelogs/1005.txt
@@ -0,0 +1,17 @@
+Nytt
+• Stöd för Android Auto
+• Flödesgrupper kan ställas in som flikar på huvudskärmen
+• [YouTube] Dela som tillfällig spellista
+• [SoundCloud] Gilla-kanalflik
+
+Förbättrat
+• Bättre tips för sökfältet
+• Visa hämtningsdatum i Hämtningar
+• Använd Android 13 per- app språk
+
+Fixat
+• Fixade textfärger i mörkt läge
+• [YouTube] Fixade att spellistor inte laddade mer än 100 objekt
+• [YouTube] Fixade saknade rekommenderade videor
+• Fixade krascher i historiklistvyn
+• Fixade tidsstämplar i kommentarsvar
diff --git a/fastlane/metadata/android/sv/changelogs/1006.txt b/fastlane/metadata/android/sv/changelogs/1006.txt
new file mode 100644
index 000000000..5fae37d22
--- /dev/null
+++ b/fastlane/metadata/android/sv/changelogs/1006.txt
@@ -0,0 +1,9 @@
+# Förbättrat
+Behåll aktuell spelare när du klickar på tidsstämplar
+Försök att återställa väntande nedladdningsuppdrag när det är möjligt
+Lägg till alternativ för att ta bort en nedladdning utan att också ta bort filen
+Överläggsbehörighet: visa förklarande dialogruta för Android > R
+Stöd för att öppna on.soundcloud-länkar
+Åtgärdade formatering av korta antal för Android-versioner under 7
+Åtgärdade Ghost Notifications
+Åtgärdade för SRT-undertextfiler
diff --git a/fastlane/metadata/android/th/changelogs/1000.txt b/fastlane/metadata/android/th/changelogs/1000.txt
new file mode 100644
index 000000000..f80fa2800
--- /dev/null
+++ b/fastlane/metadata/android/th/changelogs/1000.txt
@@ -0,0 +1,13 @@
+ที่มีการปรับปรุง
+• สร้างรายการเพลงที่สามารถคลิกให้แสดงได้โดยมีเนื้อหาเพื่มขึ้น/ลดลง
+• [PeerTube] แฮนเดิล `subscribeto.me` ลิงค์ของอินสแตนส์จะขึ้นอัตโนมัติ
+• • • เริ่มต้นด้วยรายการเดียวในประวัติของหน้าจอ
+
+ที่มีการปรับปรุง
+• ปุ่มการมองเห็นของ RSS
+• พรีวิวแท็บตัวอย่างที่มีการขัดข้อง
+• แก้ไขหน้าปกของเพลย์ลิสต์ที่ไม่ขึ้น
+• แก้ไขการตั้งค่าการดาวน์โหลดก่อนที่จะปรากฏ
+• แก้ไขรายการที่เกี่ยวข้องกับคิวป๊อปอัป
+• แก้ไขลำดับในเพลย์ลิสต์ลงในรายการที่จะเล่น
+• ปรับแต่งเค้าโครงรายการบุ๊กมาร์กของเพลย์ลิสต์
diff --git a/fastlane/metadata/android/th/full_description.txt b/fastlane/metadata/android/th/full_description.txt
new file mode 100644
index 000000000..e75af94af
--- /dev/null
+++ b/fastlane/metadata/android/th/full_description.txt
@@ -0,0 +1 @@
+NewPipe จะไม่ใช้เฟรมเวิร์กของกูเกิลที่มีหรือ API ของยูทูบ โดยแค่นำโครงสร้างของเว็บไซต์เพื่อนำข้อมูลที่ต้องการ ยังไงก็ตามตัวแอปก็สามารถใช้งานได้โดยไม่ต้องติดตั้งบริการของกูเกิล คุณไม่ต้องมีบัญชียูทูปเพื่อใช้ NewPipe, และตัว FLOSS
diff --git a/fastlane/metadata/android/th/short_description.txt b/fastlane/metadata/android/th/short_description.txt
new file mode 100644
index 000000000..211644bbc
--- /dev/null
+++ b/fastlane/metadata/android/th/short_description.txt
@@ -0,0 +1 @@
+ยูทูปแบบฟรีที่เบาสําหรับแอนดรอยด์
diff --git a/fastlane/metadata/android/tr/changelogs/1005.txt b/fastlane/metadata/android/tr/changelogs/1005.txt
new file mode 100644
index 000000000..46b3142f7
--- /dev/null
+++ b/fastlane/metadata/android/tr/changelogs/1005.txt
@@ -0,0 +1,17 @@
+Yeni
+• Android Auto desteği eklendi
+• Akış gruplarının ana ekran sekmeleri olarak ayarlanmasına izin verme
+• [YouTube] Geçici oynatma listesi olarak paylaşma
+• [SoundCloud] Beğenilen kanal sekmesi
+
+Geliştirildi
+• Daha iyi arama çubuğu önerileri
+• İndirilenler'de indirme tarihini gösterimi
+• Android 13 uygulama başı dil kullanma
+
+Düzeltildi
+• Karanlık modda bozuk metin renkleri düzeltildi
+• [YouTube] 100'den fazla öğeyi yüklemeyen oynatma listeleri düzeltildi
+• [YouTube] Eksik önerilen videolar düzeltildi
+• Geçmiş listesi görünümündeki çökmeler düzeltildi
+• Yorum yanıtlarındaki zaman damgaları düzeltildi
diff --git a/fastlane/metadata/android/uk/changelogs/1006.txt b/fastlane/metadata/android/uk/changelogs/1006.txt
new file mode 100644
index 000000000..fd79de93a
--- /dev/null
+++ b/fastlane/metadata/android/uk/changelogs/1006.txt
@@ -0,0 +1,12 @@
+# Покращено
+Зберігати поточний програвач при натисканні на часові позначки
+Намагатися відновлювати місії, що очікують завантаження, коли це можливо
+Додано опцію видалення завантаження без одночасного видалення файлу
+Дозвіл на накладання: відображення пояснювального діалогового вікна для Android > R
+Підтримка відкриття посилання на .soundcloud
+
+# Виправлено
+Виправлено форматування короткого лічильника для версій Android нижче 7
+Виправлено сповіщення-примари
+Виправлення для файлів субтитрів SRT
+Виправлено безліч збоїв
diff --git a/fastlane/metadata/android/vi/changelogs/1000.txt b/fastlane/metadata/android/vi/changelogs/1000.txt
index 209bef6f0..e812a4fea 100644
--- a/fastlane/metadata/android/vi/changelogs/1000.txt
+++ b/fastlane/metadata/android/vi/changelogs/1000.txt
@@ -1,4 +1,4 @@
-Đã cải thiện
+Những cải thiện
• Làm cho mô tả của danh sách phát có thể nhấp vào để hiển thị nhiều / ít nội dung hơn
• [PeerTube] Tự động xử lý các liên kết như 'subscribeto.me'
• Chỉ bắt đầu phát một mục trong màn hình lịch sử
diff --git a/fastlane/metadata/android/vi/changelogs/1004.txt b/fastlane/metadata/android/vi/changelogs/1004.txt
index d2086b62c..f3f9865f2 100644
--- a/fastlane/metadata/android/vi/changelogs/1004.txt
+++ b/fastlane/metadata/android/vi/changelogs/1004.txt
@@ -1 +1,3 @@
-Đã sửa lỗi YouTube không phát bất kỳ luồng nào
+Bản phát hành này khắc phục lỗi YouTube chỉ cung cấp luồng 360p.
+
+Lưu ý rằng giải pháp được sử dụng trong phiên bản này có thể chỉ là tạm thời, và về lâu dài, giao thức video SABR cần được triển khai, nhưng hiện tại các thành viên TeamNewPipe đang rất bận rộn nên chúng tôi rất mong nhận được sự giúp đỡ! https://github.com/TeamNewPipe/NewPipe/issues/12248
diff --git a/fastlane/metadata/android/vi/changelogs/1005.txt b/fastlane/metadata/android/vi/changelogs/1005.txt
new file mode 100644
index 000000000..7eeb567b7
--- /dev/null
+++ b/fastlane/metadata/android/vi/changelogs/1005.txt
@@ -0,0 +1,17 @@
+Mới
+• Hỗ trợ cho Android Auto
+• Cho phép đặt nhóm nguồn cấp dữ liệu làm tab màn hình chính
+• [YouTube] Chia sẻ dưới dạng danh sách phát tạm thời
+• [SoundCloud] Tab kênh thích
+
+Cải thiện
+• Gợi ý thanh tìm kiếm tốt hơn
+• Hiển thị ngày tải xuống trong mục Tải xuống
+• Sử dụng cài đặt ngôn ngữ cho từng ứng dụng (Android 13+)
+
+Đã sửa
+• Màu chữ bị hỏng ở chế độ tối
+• [YouTube] Danh sách phát không tải được hơn 100 mục
+• [YouTube] Thiếu video được đề xuất
+• Sập trong Lịch sử
+• Dấu thời gian trong phần trả lời bình luận
diff --git a/fastlane/metadata/android/vi/changelogs/64.txt b/fastlane/metadata/android/vi/changelogs/64.txt
index 3ba81c8e4..bd932e509 100644
--- a/fastlane/metadata/android/vi/changelogs/64.txt
+++ b/fastlane/metadata/android/vi/changelogs/64.txt
@@ -1,7 +1,7 @@
### Cải thiện
- Thêm tính năng giới hạn độ phân giải video nếu đang sử dụng dữ liệu di động (yêu cầu #1339)
- Ghi nhớ độ sáng màn hình trong phiên (yêu cầu #1442)
-- Cải thiện hiệu năng của trình tải cho các CPU có hiệu năng yếu (vấn đề #1431)
+- Cải thiện tốc độ tải xuống cho các CPU có hiệu năng yếu (vấn đề #1431)
- Hỗ trợ cho media session (yêu cầu #1433)
### Sửa lỗi
diff --git a/fastlane/metadata/android/vi/changelogs/65.txt b/fastlane/metadata/android/vi/changelogs/65.txt
index de47bd38b..3b25b25d7 100644
--- a/fastlane/metadata/android/vi/changelogs/65.txt
+++ b/fastlane/metadata/android/vi/changelogs/65.txt
@@ -1,10 +1,9 @@
-##Cải thiện:
-### Cải tiến
+### Cải thiện:
- Tắt hoạt ảnh biểu tượng burgermenu #1486
-- hoàn tác xóa các bản tải xuống # 1472
+- Hoàn tác xóa các bản tải xuống # 1472
- Tùy chọn tải xuống trong menu chia sẻ #1498
-- Đã thêm tùy chọn chia sẻ vào menu nhấn dài #1454
+- Đã thêm tùy chọn chia sẻ vào menu nhấn giữ #1454
- Thu nhỏ trình phát chính ở lối ra #1354
- Cập nhật phiên bản thư viện và sửa lỗi sao lưu cơ sở dữ liệu #1510
- Cập nhật ExoPlayer 2.8.2 #1392
diff --git a/fastlane/metadata/android/vi/full_description.txt b/fastlane/metadata/android/vi/full_description.txt
index 63f66cb18..81ecf1d63 100644
--- a/fastlane/metadata/android/vi/full_description.txt
+++ b/fastlane/metadata/android/vi/full_description.txt
@@ -1 +1 @@
-NewPipe không sử dụng bất kì thư viện nào của Google, hay API của YouTube. Nó chỉ đọc và phân tích trang web để lấy thông tin cần thiết. Vì thế, ứng dụng này có thể dùng được trên các thiết bị không có cài đặt Dịch vụ của Google Play. Bạn cũng không cần tài khoản YouTube để sử dụng NewPipe, và ứng dụng này là mã nguồn mở (FLOSS).
+NewPipe không sử dụng bất kì thư viện nào của Google, hay API của YouTube. Nó chỉ đọc và phân tích trang web để lấy thông tin cần thiết. Vì thế, ứng dụng này có thể dùng được trên các thiết bị không có cài đặt Dịch vụ của Google. Bạn cũng không cần tài khoản YouTube để sử dụng NewPipe, và ứng dụng này là mã nguồn mở (FLOSS).
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/1002.txt b/fastlane/metadata/android/zh-Hans/changelogs/1002.txt
index 8a5424c9e..ae42beccc 100644
--- a/fastlane/metadata/android/zh-Hans/changelogs/1002.txt
+++ b/fastlane/metadata/android/zh-Hans/changelogs/1002.txt
@@ -1 +1,4 @@
-修复YouTube无法播放任何视频
+修复YouTube不播放任何串流的问题
+
+此版本只解决了阻止最紧迫的阻止 YouTube 视频详情加载的错误。
+我们知道有其他问题,会在不久后发布另一个版本解决它们。
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/1003.txt b/fastlane/metadata/android/zh-Hans/changelogs/1003.txt
index 8a5424c9e..195ffeb58 100644
--- a/fastlane/metadata/android/zh-Hans/changelogs/1003.txt
+++ b/fastlane/metadata/android/zh-Hans/changelogs/1003.txt
@@ -1 +1,6 @@
-修复YouTube无法播放任何视频
+修复 YouTube 错误的热修复版本:
+• [YouTube]修复不加载任何视频的问题,修复播放视频时的 HTTP 403 错误, 恢复某些年龄受限视频的播放
+• 修复字幕尺寸未被更改的问题
+• 修复打开串流时下载两次信息的问题
+• [Soundcloud] 删除不可播放的受 DRM 保护的串流
+• 更新翻译
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/1004.txt b/fastlane/metadata/android/zh-Hans/changelogs/1004.txt
index 8a5424c9e..8b667904a 100644
--- a/fastlane/metadata/android/zh-Hans/changelogs/1004.txt
+++ b/fastlane/metadata/android/zh-Hans/changelogs/1004.txt
@@ -1 +1,3 @@
-修复YouTube无法播放任何视频
+此版本修复 YouTube 只提供 360p 串流的问题。
+
+注意此版本部署的解决方案可能是临时性的,长期来看需要使用 SABR 视频协议,但 Newpipe 团队成员目前没空,我们十分感谢任何帮助!https://github.com/TeamNewPipe/NewPipe/issues/12248
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/1005.txt b/fastlane/metadata/android/zh-Hans/changelogs/1005.txt
new file mode 100644
index 000000000..baf746b18
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/1005.txt
@@ -0,0 +1,16 @@
+新增
+• 新增对 Android Auto 的支持
+• 允许将信息流分组设置为主屏幕标签页
+• [YouTube] 以临时播放列表的形式分享
+• [SoundCloud] 新增“喜欢”频道标签页
+
+改进
+• 优化搜索栏提示
+• 在“下载”中显示下载日期
+• 使用 Android 13 的应用内语言
+修复
+• 修复深色模式下文本颜色显示错误
+• [YouTube] 修复播放列表加载超过 100 个项目时无法加载的问题
+• [YouTube] 修复推荐视频缺失的问题
+• 修复历史记录列表视图中的崩溃问题
+• 修复评论回复中的时间戳显示错误
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/1006.txt b/fastlane/metadata/android/zh-Hans/changelogs/1006.txt
new file mode 100644
index 000000000..a3a089068
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/1006.txt
@@ -0,0 +1,16 @@
+# 改进
+单击时间戳时保持当前播放器
+尽可能恢复未完成的下载任务
+新增选项,允许删除下载项而不删除文件
+叠加层权限:在 Android R 及以上版本中显示说明对话框
+支持打开 on.soundcloud 链接
+大量小改进和优化
+
+# 修复
+修复 Android 7 以下版本短计数格式问题
+修复幽灵通知
+修复 SRT 字幕文件问题
+修复大量崩溃问题
+
+# 开发
+内部代码现代化
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/991.txt b/fastlane/metadata/android/zh-Hans/changelogs/991.txt
new file mode 100644
index 000000000..c4ca761f4
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/991.txt
@@ -0,0 +1,13 @@
+新增
+• 在错误面板中添加“在浏览器中打开”按钮
+• 新增以列表形式显示频道组的选项
+• [YouTube] 长按视频片段即可分享时间戳 URL
+• 在迷你播放器中添加播放队列按钮
+
+改进
+• 新增冰岛语本地化并更新了其他多种语言的翻译
+• 多项内部改进
+
+修复
+• 修复多个崩溃问题
+• [YouTube] 修复部分国家/地区频道加载、非专用源播放以及播放问题
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/992.txt b/fastlane/metadata/android/zh-Hans/changelogs/992.txt
new file mode 100644
index 000000000..ca8e1733d
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/992.txt
@@ -0,0 +1,17 @@
+新增
+• 视频详情页显示订阅者数量
+• 从播放队列下载
+• 永久设置播放列表缩略图
+• 长按话题标签和链接
+• 卡片视图模式
+
+改进
+• 更大的迷你播放器关闭按钮
+• 更流畅的缩略图缩放
+• 目标平台:Android 13 (API 33)
+• 快进/快退操作不再导致播放器暂停
+
+修复
+• 修复 DeX/鼠标上的叠加层问题
+• 允许后台播放,无需单独的音频流
+• 其他 YouTube 相关问题修复及更多…
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/993.txt b/fastlane/metadata/android/zh-Hans/changelogs/993.txt
new file mode 100644
index 000000000..abe5b8f27
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/993.txt
@@ -0,0 +1,12 @@
+新增
+• 添加重复播放列表时发出警告,并添加删除按钮
+• 允许忽略硬件按钮
+• 允许在信息流中隐藏已观看但未完成的视频
+
+改进
+• 在大屏幕上使用更多网格列
+• 使进度指示器与设置保持一致
+
+修复
+• 修复在 Android 11 及更高版本上打开浏览器 URL、下载和外部播放器的问题
+• 修复在 MIUI 系统上全屏交互需要点击两次的问题
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/994.txt b/fastlane/metadata/android/zh-Hans/changelogs/994.txt
new file mode 100644
index 000000000..38bfed7d0
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/994.txt
@@ -0,0 +1,15 @@
+新增
+• 支持多音轨/多语言
+• 允许在屏幕任意一侧使用手势调节音量和亮度
+• 支持在屏幕底部显示主标签页
+
+改进
+• [Bandcamp] 处理付费墙后的曲目
+
+修复
+• [YouTube] 修复流媒体播放的 403 HTTP 错误
+• 修复从播放列表视图切换到主播放器时播放器黑屏的问题
+• 修复播放器服务内存泄漏问题
+• [PeerTube] 上传者和子频道头像互换的问题
+
+以及更多
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/995.txt b/fastlane/metadata/android/zh-Hans/changelogs/995.txt
new file mode 100644
index 000000000..4cd4d2b80
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/995.txt
@@ -0,0 +1,16 @@
+新增
+• 支持频道标签页
+• 可选择图像质量
+• 获取所有图像的 URL
+
+改进
+• 播放器界面更易于访问
+• 改进仅下载视频时的音频选择
+• 可选择在共享播放列表内容中包含播放列表和视频名称
+
+修复
+• [YouTube] 修复获取点赞数的问题
+• 修复播放器无响应的弹出窗口和崩溃问题
+• 修复语言选择器中选择错误语言的问题
+• 修复播放器音频焦点未响应静音设置的问题
+• 修复播放列表项目添加功能偶尔失效的问题
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/996.txt b/fastlane/metadata/android/zh-Hans/changelogs/996.txt
new file mode 100644
index 000000000..4773b420b
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/996.txt
@@ -0,0 +1,2 @@
+修复了在 media.ccc.de 中打开频道/会议时出现的 NullPointerException 异常。
+圣诞怪杰试图破坏我们送给大家的圣诞礼物,但我们已经解决了这个问题。
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/997.txt b/fastlane/metadata/android/zh-Hans/changelogs/997.txt
new file mode 100644
index 000000000..a7cd06bd6
--- /dev/null
+++ b/fastlane/metadata/android/zh-Hans/changelogs/997.txt
@@ -0,0 +1,17 @@
+新增
+• 添加评论回复
+• 允许重新排序播放列表
+• 显示播放列表描述和时长
+• 允许重置设置
+
+改进
+• [Android 13+] 恢复自定义通知操作
+• 请求更新检查的同意
+• 允许在缓冲期间播放/暂停通知
+• 重新排序部分设置
+
+修复
+• [YouTube] 修复评论无法加载的问题,以及其他修复和改进
+• 修复设置导入中的漏洞并切换到 JSON 格式
+• 修复各种下载问题
+• 精简搜索文本
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/998.txt b/fastlane/metadata/android/zh-Hans/changelogs/998.txt
index 8a5424c9e..edffb7593 100644
--- a/fastlane/metadata/android/zh-Hans/changelogs/998.txt
+++ b/fastlane/metadata/android/zh-Hans/changelogs/998.txt
@@ -1 +1,4 @@
-修复YouTube无法播放任何视频
+修复 YouTube 因 HTTP 403 错误不播放任何串流的问题
+
+还没修复 YouTube 视频中间偶尔的 403 错误.
+该问题会尽快在另一个热修复版本中得以解决。
diff --git a/fastlane/metadata/android/zh-Hans/changelogs/999.txt b/fastlane/metadata/android/zh-Hans/changelogs/999.txt
index 8a5424c9e..791c12314 100644
--- a/fastlane/metadata/android/zh-Hans/changelogs/999.txt
+++ b/fastlane/metadata/android/zh-Hans/changelogs/999.txt
@@ -1 +1,12 @@
-修复YouTube无法播放任何视频
+此热修复版本修复 YouTube 视频播放中的 HTTP 403 错误。
+
+新功能
+• [SoundCloud] 支持 on.soundcloud.com URLs
+
+改进
+• [Bandcamp] 在电台 kiosk 中显示附加信息
+
+修复
+• [YouTube] 视频开头或当中偶然的 403 错误
+• [YouTube] 从更多频道标头类型提取头像和横幅
+• [Bandcamp] 多个故障和始终使用 HTTPS
diff --git a/fastlane/metadata/android/zh_Hant_HK/changelogs/1005.txt b/fastlane/metadata/android/zh_Hant_HK/changelogs/1005.txt
new file mode 100644
index 000000000..8389ad0be
--- /dev/null
+++ b/fastlane/metadata/android/zh_Hant_HK/changelogs/1005.txt
@@ -0,0 +1,17 @@
+新功能
+• 加入咗對 Android Auto 應用程式嘅支援
+• 允許將資訊提供群組設定為主螢幕標籤
+• 【 YouTube 】可分享為臨時播放清單
+• 【 SoundCloud 】可設定為最喜愛頻道標籤
+
+改善
+• 更好嘅搜尋列提示
+• 「下載」介面會顯示下載日期
+• 使用 Android 13為所有應用程式嘅語言
+
+修復
+• 修復咗深色模式下破碎嘅文字顏色
+• 修復咗【 YouTube 】播放清單無法載入超過100 個項目嘅問題
+• 修復咗【 YouTube 】推薦影片消失嘅問題
+• 修復咗睇緊播放記錄期間會死機嘅問題
+• 修復咗留言同回覆入面嘅時間戳記
diff --git a/fastlane/metadata/android/zh_Hant_HK/changelogs/64.txt b/fastlane/metadata/android/zh_Hant_HK/changelogs/64.txt
new file mode 100644
index 000000000..65e8afaf9
--- /dev/null
+++ b/fastlane/metadata/android/zh_Hant_HK/changelogs/64.txt
@@ -0,0 +1,8 @@
+### 改善
+- 加入咗喺使用流動數據時限制影片質素嘅功能。#1339
+- 會記錄並使用你設定嘅亮度。#1442
+- 改善在較弱CPU上嘅設備嘅下載效能。#1431
+- 加入咗(可用)媒體支援。#1433
+
+### 修復
+- 修復咗打開下載時發生死機嘅問題(修復版本已推出)。#1441
diff --git a/fastlane/metadata/android/zh_Hant_HK/changelogs/65.txt b/fastlane/metadata/android/zh_Hant_HK/changelogs/65.txt
new file mode 100644
index 000000000..eaa087920
--- /dev/null
+++ b/fastlane/metadata/android/zh_Hant_HK/changelogs/65.txt
@@ -0,0 +1,26 @@
+### 改善
+
+- 停用漢堡選單圖示動畫 #1486
+- 還原已刪除嘅下載項目 #1472
+- 喺分享選單中加入下載選項 #1498
+- 喺長按選單中加入分享選項 #1454
+- 離開時最小化主播放器 #1354
+- 更新資料庫版本並修復備份問題 #1510
+- ExoPlayer 2.8.2 更新 #1392
+- 重新設計播放速度控制對話框,支援更細緻嘅速度調整步幅。
+- 加入靜音時快轉嘅切換選項,有助於聽有聲書或某啲音樂類型,提供更流暢嘅體驗(但可能會令某啲有大量靜音段落嘅歌曲播放出現問題 =\\)。
+- 重構媒體來源解析方式,令播放器可以內部傳遞媒體同時附帶嘅中繼資料,而唔需要手動處理。播放一開始就可以直接使用統一來源嘅中繼資料。
+- 修復遠端播放清單中繼資料喺開啟播放清單片段時未能更新嘅問題。
+- 各種 UI 修復:#1383,例如背景播放器通知控制改為固定白色、彈出播放器更容易關閉。
+- 使用新架構重構嘅多服務擷取器
+
+### 修復項目
+
+- 修復咗 #1440 影片資訊版面錯誤配置 #1491
+- 修復咗無法觀看播放記錄問題 #1497
+- #1495:當使用者打開播放清單時即時更新中繼資料(縮圖、標題、影片數量)。
+- #1475:當使用者喺詳細頁面用外部播放器播放影片時,會喺資料庫中登記一次觀看記錄。
+- 修復咗彈出模式下螢幕逾時問題 #1463(已修復 #640)
+- 主播放器修復 #1509
+- [#1412] 修復咗重複播放模式喺接收新指示時,播放器處於背景導致 NPE 嘅問題。
+- 修復咗未授權彈出權限時將播放器最小化到彈出視窗不會關掉播放器嘅問題。
diff --git a/fastlane/metadata/android/zh_Hant_HK/changelogs/66.txt b/fastlane/metadata/android/zh_Hant_HK/changelogs/66.txt
new file mode 100644
index 000000000..d5a6d607a
--- /dev/null
+++ b/fastlane/metadata/android/zh_Hant_HK/changelogs/66.txt
@@ -0,0 +1,33 @@
+# v0.13.7 更新日誌
+
+### 修復
+- 修復咗 v0.13.6 中排序篩選器嘅問題
+
+# v0.13.6 更新日誌
+
+### 改善
+
+- 停用漢堡選單圖示動畫 #1486
+- 還原已刪除嘅下載項目 #1472
+- 喺分享選單中加入下載選項 #1498
+- 喺長按選單中加入分享選項 #1454
+- 離開時最小化主播放器 #1354
+- 更新資料庫版本並修復備份問題 #1510
+- ExoPlayer 2.8.2 更新 #1392
+- 重新設計播放速度控制對話框,支援更細緻嘅速度調整步幅。
+- 加入靜音時快轉嘅切換選項,有助於聽有聲書或某啲音樂類型,提供更流暢嘅體驗(但可能會令某啲有大量靜音段落嘅歌曲播放出現問題 =\\)。
+- 重構媒體來源解析方式,令播放器可以內部傳遞媒體同時附帶嘅中繼資料,而唔需要手動處理。播放一開始就可以直接使用統一來源嘅中繼資料。
+- 修復遠端播放清單中繼資料喺開啟播放清單片段時未能更新嘅問題。
+- 各種 UI 修復:#1383,例如背景播放器通知控制改為固定白色、彈出播放器更容易關閉。
+- 使用新架構重構嘅多服務擷取器
+
+### 修復項目
+
+- 修復咗 #1440 影片資訊版面錯誤配置 #1491
+- 修復咗無法觀看播放記錄問題 #1497
+- #1495:當使用者打開播放清單時即時更新中繼資料(縮圖、標題、影片數量)。
+- #1475:當使用者喺詳細頁面用外部播放器播放影片時,會喺資料庫中登記一次觀看記錄。
+- 修復咗彈出模式下螢幕逾時問題 #1463(已修復 #640)
+- 主播放器修復 #1509
+- [#1412] 修復咗重複播放模式喺接收新指示時,播放器處於背景導致 NPE 嘅問題。
+- 修復咗未授權彈出權限時將播放器最小化到彈出視窗不會關掉播放器嘅問題。
diff --git a/fastlane/metadata/android/zh_Hant_HK/changelogs/68.txt b/fastlane/metadata/android/zh_Hant_HK/changelogs/68.txt
new file mode 100644
index 000000000..00b67b1ea
--- /dev/null
+++ b/fastlane/metadata/android/zh_Hant_HK/changelogs/68.txt
@@ -0,0 +1,31 @@
+# v0.14.1 更新內容
+
+### 修復項目
+- 修復咗無法解密影片網址嘅問題 #1659
+- 修復咗影片描述連結擷取唔準確嘅問題 #1657
+
+# v0.14.0 更新內容
+
+### 新功能
+- 全新抽屜式選單設計 #1461
+- 可自訂嘅主頁介面 #1461
+
+### 改善項目
+- 重新設計手勢控制功能 #1604
+- 加入新方式關閉彈出播放器 #1597
+
+### 修復項目
+- 修復訂閱人數無法取得時出錯嘅問題。已關閉 #1649
+ - 當無法取得訂閱人數時,會顯示「無法取得訂閱人數」
+- 修復 YouTube 播放清單為空時出現 NPE 錯誤
+- 快速修復 SoundCloud 互動資訊站問題
+- 重構並修復錯誤 #1623
+ - 修復循環搜尋結果問題 #1562
+ - 修復進度條未正確排版問題
+ - 修復 YouTube Premium 影片未正確封鎖問題
+ - 修復影片有時無法載入(因 DASH 解析問題)
+ - 修復影片描述中連結無法點擊問題
+ - 當使用者嘗試下載至外置 SD 卡時顯示警告
+ - 修復「無內容顯示」錯誤觸發回報問題
+ - 修復 Android 8.1 背景播放器未顯示縮圖問題 [詳情請參閱](https://github.com/TeamNewPipe/NewPipe/issues/943)
+- 修復廣播接收器註冊問題。已關閉 #1641
diff --git a/gradle.properties b/gradle.properties
index ed32303da..01e1aa01f 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -4,3 +4,6 @@ android.nonTransitiveRClass=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx2048M --add-opens jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
systemProp.file.encoding=utf-8
+
+# https://docs.gradle.org/current/userguide/configuration_cache.html
+org.gradle.configuration-cache=true
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
new file mode 100644
index 000000000..2f643413b
--- /dev/null
+++ b/gradle/libs.versions.toml
@@ -0,0 +1,139 @@
+#
+# SPDX-FileCopyrightText: 2025 NewPipe e.V.
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+[versions]
+acra = "5.13.1"
+agp = "8.13.2"
+appcompat = "1.7.1"
+assertj = "3.27.6"
+autoservice-google = "1.1.1"
+autoservice-zacsweers = "1.2.0"
+bridge = "v2.0.2"
+cardview = "1.0.0"
+checkstyle = "12.2.0"
+constraintlayout = "2.2.1"
+core = "1.17.0"
+desugar = "2.1.5"
+documentfile = "1.1.0"
+exoplayer = "2.19.1"
+fragment = "1.8.9"
+groupie = "2.10.1"
+jsoup = "1.21.2"
+junit = "4.13.2"
+junit-ext = "1.3.0"
+kotlin = "2.2.21"
+ksp = "2.3.2"
+ktlint = "1.8.0"
+leakcanary = "2.14"
+lifecycle = "2.9.4" # Newer versions require minSdk >= 23
+localbroadcastmanager = "1.1.0"
+markwon = "4.6.2"
+material = "1.11.0"
+media = "1.7.1"
+mockitoCore = "5.21.0"
+okhttp = "5.3.2"
+phoenix = "3.0.0"
+#noinspection NewerVersionAvailable,GradleDependency --> 2.8 is the last version, not 2.71828!
+picasso = "2.8"
+preference = "1.2.1"
+prettytime = "5.0.8.Final"
+recyclerview = "1.4.0"
+room = "2.7.2" # Newer versions require minSdk >= 23
+runner = "1.7.0"
+rxandroid = "3.0.2"
+rxbinding = "4.0.0"
+rxjava = "3.1.12"
+sonarqube = "7.2.1.6560"
+statesaver = "1.4.1" # TODO: Drop because it is deprecated and incompatible with KSP2
+stetho = "1.6.0"
+swiperefreshlayout = "1.2.0"
+# You can use a local version by uncommenting a few lines in settings.gradle
+# Or you can use a commit you pushed to GitHub by just replacing TeamNewPipe with your GitHub
+# name and the commit hash with the commit hash of the (pushed) commit you want to test
+# This works thanks to JitPack: https://jitpack.io/
+teamnewpipe-filepicker = "5.0.0"
+teamnewpipe-nanojson = "e9d656ddb49a412a5a0a5d5ef20ca7ef09549996"
+# WORKAROUND: if you get errors with the NewPipeExtractor dependency, replace `v0.XX.Y` with
+# the corresponding commit hash, since JitPack sometimes deletes artifacts.
+# If there’s already a git hash, just add more of it to the end (or remove a letter)
+# to cause jitpack to regenerate the artifact.
+teamnewpipe-newpipe-extractor = "v0.25.0"
+viewpager2 = "1.1.0"
+webkit = "1.14.0"
+work = "2.10.5" # Newer versions require minSdk >= 23
+
+[libraries]
+acra-core = { module = "ch.acra:acra-core", version.ref = "acra" }
+android-desugar = { module = "com.android.tools:desugar_jdk_libs_nio", version.ref = "desugar" }
+androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
+androidx-cardview = { module = "androidx.cardview:cardview", version.ref = "cardview" }
+androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "constraintlayout" }
+androidx-core = { module = "androidx.core:core-ktx", version.ref = "core" }
+androidx-documentfile = { module = "androidx.documentfile:documentfile", version.ref = "documentfile" }
+androidx-fragment = { module = "androidx.fragment:fragment-ktx", version.ref = "fragment" }
+androidx-junit = { module = "androidx.test.ext:junit", version.ref = "junit-ext" }
+androidx-lifecycle-livedata = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycle" }
+androidx-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycle" }
+androidx-localbroadcastmanager = { module = "androidx.localbroadcastmanager:localbroadcastmanager", version.ref = "localbroadcastmanager" }
+androidx-media = { module = "androidx.media:media", version.ref = "media" }
+androidx-preference = { module = "androidx.preference:preference", version.ref = "preference" }
+androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" }
+androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
+androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
+androidx-room-rxjava3 = { module = "androidx.room:room-rxjava3", version.ref = "room" }
+androidx-room-testing = { module = "androidx.room:room-testing", version.ref = "room" }
+androidx-runner = { module = "androidx.test:runner", version.ref = "runner" }
+androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "swiperefreshlayout" }
+androidx-viewpager2 = { module = "androidx.viewpager2:viewpager2", version.ref = "viewpager2" }
+androidx-webkit = { module = "androidx.webkit:webkit", version.ref = "webkit" }
+androidx-work-runtime = { module = "androidx.work:work-runtime", version.ref = "work" }
+androidx-work-rxjava3 = { module = "androidx.work:work-rxjava3", version.ref = "work" }
+assertj-core = { module = "org.assertj:assertj-core", version.ref = "assertj" }
+evernote-statesaver-compiler = { module = "com.evernote:android-state-processor", version.ref = "statesaver" }
+evernote-statesaver-core = { module = "com.evernote:android-state", version.ref = "statesaver" }
+facebook-stetho-core = { module = "com.facebook.stetho:stetho", version.ref = "stetho" }
+facebook-stetho-okhttp3 = { module = "com.facebook.stetho:stetho-okhttp3", version.ref = "stetho" }
+google-android-material = { module = "com.google.android.material:material", version.ref = "material" }
+google-autoservice-annotations = { module = "com.google.auto.service:auto-service-annotations", version.ref = "autoservice-google" }
+google-exoplayer-core = { module = "com.google.android.exoplayer:exoplayer-core", version.ref = "exoplayer" }
+google-exoplayer-dash = { module = "com.google.android.exoplayer:exoplayer-dash", version.ref = "exoplayer" }
+google-exoplayer-database = { module = "com.google.android.exoplayer:exoplayer-database", version.ref = "exoplayer" }
+google-exoplayer-datasource = { module = "com.google.android.exoplayer:exoplayer-datasource", version.ref = "exoplayer" }
+google-exoplayer-hls = { module = "com.google.android.exoplayer:exoplayer-hls", version.ref = "exoplayer" }
+google-exoplayer-mediasession = { module = "com.google.android.exoplayer:extension-mediasession", version.ref = "exoplayer" }
+google-exoplayer-smoothstreaming = { module = "com.google.android.exoplayer:exoplayer-smoothstreaming", version.ref = "exoplayer" }
+google-exoplayer-ui = { module = "com.google.android.exoplayer:exoplayer-ui", version.ref = "exoplayer" }
+jakewharton-phoenix = { module = "com.jakewharton:process-phoenix", version.ref = "phoenix" }
+jakewharton-rxbinding = { module = "com.jakewharton.rxbinding4:rxbinding", version.ref = "rxbinding" }
+jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" }
+junit = { module = "junit:junit", version.ref = "junit" }
+lisawray-groupie-core = { module = "com.github.lisawray.groupie:groupie", version.ref = "groupie" }
+lisawray-groupie-viewbinding = { module = "com.github.lisawray.groupie:groupie-viewbinding", version.ref = "groupie" }
+livefront-bridge = { module = "com.github.livefront:bridge", version.ref = "bridge" }
+mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockitoCore" }
+newpipe-extractor = { module = "com.github.TeamNewPipe:NewPipeExtractor", version.ref = "teamnewpipe-newpipe-extractor" }
+newpipe-filepicker = { module = "com.github.TeamNewPipe:NoNonsense-FilePicker", version.ref = "teamnewpipe-filepicker" }
+newpipe-nanojson = { module = "com.github.TeamNewPipe:nanojson", version.ref = "teamnewpipe-nanojson" }
+noties-markwon-core = { module = "io.noties.markwon:core", version.ref = "markwon" }
+noties-markwon-linkify = { module = "io.noties.markwon:linkify", version.ref = "markwon" }
+ocpsoft-prettytime = { module = "org.ocpsoft.prettytime:prettytime", version.ref = "prettytime" }
+pinterest-ktlint = { module = "com.pinterest.ktlint:ktlint-cli", version.ref = "ktlint" }
+puppycrawl-checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" }
+reactivex-rxandroid = { module = "io.reactivex.rxjava3:rxandroid", version.ref = "rxandroid" }
+reactivex-rxjava = { module = "io.reactivex.rxjava3:rxjava", version.ref = "rxjava" }
+squareup-leakcanary-core = { module = "com.squareup.leakcanary:leakcanary-android-core", version.ref = "leakcanary" }
+squareup-leakcanary-plumber = { module = "com.squareup.leakcanary:plumber-android", version.ref = "leakcanary" }
+squareup-leakcanary-watcher = { module = "com.squareup.leakcanary:leakcanary-object-watcher-android", version.ref = "leakcanary" }
+squareup-okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
+squareup-picasso = { module = "com.squareup.picasso:picasso", version.ref = "picasso" }
+zacsweers-autoservice-compiler = { module = "dev.zacsweers.autoservice:auto-service-ksp", version.ref = "autoservice-zacsweers" }
+
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+google-ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
+jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
+jetbrains-kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" } # Needed for statesaver
+jetbrains-kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" }
+sonarqube = { id = "org.sonarqube", version.ref = "sonarqube" }
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index c1962a79e..f8e1ee312 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 4ea536e77..8a848873f 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,8 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
+distributionSha256Sum=72f44c9f8ebcb1af43838f45ee5c4aa9c5444898b3468ab3f4af7b6076c5bc3f
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index aeb74cbb4..adff685a0 100755
--- a/gradlew
+++ b/gradlew
@@ -1,7 +1,7 @@
#!/bin/sh
#
-# Copyright © 2015-2021 the original authors.
+# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -83,7 +85,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -111,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -130,10 +132,13 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
@@ -141,7 +146,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
+ # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -149,7 +154,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
+ # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -166,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -198,16 +202,15 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-# Collect all arguments for the java command;
-# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
-# shell script including quotes and variable substitutions, so put them in
-# double quotes to make sure that they get re-expanded; and
-# * put everything else in single quotes, so that it's not re-expanded.
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/gradlew.bat b/gradlew.bat
index 6689b85be..e509b2dd8 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -57,22 +59,21 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/settings.gradle b/settings.gradle
deleted file mode 100644
index 0338fde6c..000000000
--- a/settings.gradle
+++ /dev/null
@@ -1,11 +0,0 @@
-include ':app'
-
-// Use a local copy of NewPipe Extractor by uncommenting the lines below.
-// We assume, that NewPipe and NewPipe Extractor have the same parent directory.
-// If this is not the case, please change the path in includeBuild().
-
-//includeBuild('../NewPipeExtractor') {
-// dependencySubstitution {
-// substitute module('com.github.TeamNewPipe:NewPipeExtractor') using project(':extractor')
-// }
-//}
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 000000000..60a40c985
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,33 @@
+/*
+ * SPDX-FileCopyrightText: 2025 NewPipe e.V.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+pluginManagement {
+ repositories {
+ gradlePluginPortal()
+ google()
+ mavenCentral()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ maven(url = "https://jitpack.io")
+ maven(url = "https://repo.clojars.org")
+ }
+}
+include (":app")
+
+// Use a local copy of NewPipe Extractor by uncommenting the lines below.
+// We assume, that NewPipe and NewPipe Extractor have the same parent directory.
+// If this is not the case, please change the path in includeBuild().
+
+//includeBuild("../NewPipeExtractor") {
+// dependencySubstitution {
+// substitute(module("com.github.TeamNewPipe:NewPipeExtractor"))
+// .using(project(":extractor"))
+// }
+//}