diff --git a/.github/workflows/artifact-comment.yml b/.github/workflows/artifact-comment.yml index 8528a95b..8c7d5331 100644 --- a/.github/workflows/artifact-comment.yml +++ b/.github/workflows/artifact-comment.yml @@ -26,7 +26,7 @@ jobs: steps: - name: 🔍 Get PR and Artifacts - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 with: script: | // Check if we're running from a fork (more precise detection) @@ -188,6 +188,17 @@ jobs: if (latestAppsRun) { console.log(`Getting individual job statuses for run ${latestAppsRun.id} (status: ${latestAppsRun.status}, conclusion: ${latestAppsRun.conclusion || 'none'})`); + // Map job names to our build targets. Declared outside the try so + // the catch fallback can reuse the same keys. + const jobMappings = { + 'Android Phone': ['🤖 Build Android APK (Phone)', 'build-android-phone'], + 'Android TV': ['🤖 Build Android APK (TV)', 'build-android-tv'], + 'iOS': ['🍎 Build iOS IPA (Phone)', 'build-ios-phone'], + 'iOS Unsigned': ['🍎 Build iOS IPA (Phone - Unsigned)', 'build-ios-phone-unsigned'], + 'tvOS': ['🍎 Build tvOS IPA', 'build-ios-tv'], + 'tvOS Unsigned': ['🍎 Build tvOS IPA (Unsigned)', 'build-ios-tv-unsigned'] + }; + try { // Get all jobs for this workflow run const { data: jobs } = await github.rest.actions.listJobsForWorkflowRun({ @@ -216,13 +227,6 @@ jobs: return; // Exit early } - // Map job names to our build targets - const jobMappings = { - 'Android Phone': ['🤖 Build Android APK (Phone)', 'build-android-phone'], - 'Android TV': ['🤖 Build Android APK (TV)', 'build-android-tv'], - 'iOS Phone': ['🍎 Build iOS IPA (Phone)', 'build-ios-phone'] - }; - // Create individual status for each job for (const [platform, jobNames] of Object.entries(jobMappings)) { const job = jobs.jobs.find(j => @@ -236,7 +240,9 @@ jobs: conclusion: job.conclusion, url: job.html_url, runId: latestAppsRun.id, - created_at: job.started_at || latestAppsRun.created_at + created_at: job.started_at || latestAppsRun.created_at, + started_at: job.started_at, + completed_at: job.completed_at }; console.log(`Mapped ${platform} to job: ${job.name} (${job.status}/${job.conclusion || 'none'})`); } else { @@ -247,22 +253,30 @@ jobs: conclusion: latestAppsRun.conclusion, url: latestAppsRun.html_url, runId: latestAppsRun.id, - created_at: latestAppsRun.created_at + created_at: latestAppsRun.created_at, + started_at: latestAppsRun.run_started_at, + completed_at: latestAppsRun.updated_at }; } } } catch (error) { console.log(`Failed to get jobs for run ${latestAppsRun.id}:`, error.message); - // Fallback to workflow-level status - buildStatuses['Android Phone'] = buildStatuses['Android TV'] = buildStatuses['iOS Phone'] = { + // Fallback to workflow-level status for every build target. + // Keys must match jobMappings / buildTargets statusKey values. + const fallbackStatus = { name: latestAppsRun.name, status: latestAppsRun.status, conclusion: latestAppsRun.conclusion, url: latestAppsRun.html_url, runId: latestAppsRun.id, - created_at: latestAppsRun.created_at + created_at: latestAppsRun.created_at, + started_at: latestAppsRun.run_started_at, + completed_at: latestAppsRun.updated_at }; + for (const platform of Object.keys(jobMappings)) { + buildStatuses[platform] = fallbackStatus; + } } // Collect artifacts if any job has completed successfully @@ -353,10 +367,12 @@ jobs: // Process each expected build target individually const buildTargets = [ - { name: 'Android Phone', platform: '🤖', device: '📱', statusKey: 'Android Phone', artifactPattern: /android.*phone/i }, - { name: 'Android TV', platform: '🤖', device: '📺', statusKey: 'Android TV', artifactPattern: /android.*tv/i }, - { name: 'iOS Phone', platform: '🍎', device: '📱', statusKey: 'iOS Phone', artifactPattern: /ios.*phone/i }, - { name: 'iOS TV', platform: '🍎', device: '📺', statusKey: 'iOS TV', artifactPattern: /ios.*tv/i } + { name: 'Android Phone', platform: '🤖', device: '📱 Phone', statusKey: 'Android Phone', artifactPattern: /android.*phone/i }, + { name: 'Android TV', platform: '🤖', device: '📺 TV', statusKey: 'Android TV', artifactPattern: /android.*tv/i }, + { name: 'iOS', platform: '🍎', device: '📱 Phone', statusKey: 'iOS', artifactPattern: /ios.*phone.*ipa(?!.*unsigned)/i }, + { name: 'iOS Unsigned', platform: '🍎', device: '📱 Phone Unsigned', statusKey: 'iOS Unsigned', artifactPattern: /ios.*phone.*unsigned/i }, + { name: 'tvOS', platform: '🍎', device: '📺 TV', statusKey: 'tvOS', artifactPattern: /ios.*tv.*ipa(?!.*unsigned)/i }, + { name: 'tvOS Unsigned', platform: '🍎', device: '📺 TV Unsigned', statusKey: 'tvOS Unsigned', artifactPattern: /ios.*tv.*unsigned/i } ]; for (const target of buildTargets) { @@ -371,16 +387,31 @@ jobs: let status = '⏳ Pending'; let downloadLink = '*Waiting for build...*'; - // Special case for iOS TV - show as disabled - if (target.name === 'iOS TV') { + // tvOS builds are temporarily disabled until feat/tv-interface + // is merged - show them as disabled instead of stuck pending. + if (target.name === 'tvOS' || target.name === 'tvOS Unsigned') { status = '💤 Disabled'; - downloadLink = '*Disabled for now*'; + downloadLink = '*Disabled until feat/tv-interface is merged*'; } else if (matchingStatus) { if (matchingStatus.conclusion === 'success' && matchingArtifact) { status = '✅ Complete'; const directLink = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${matchingArtifact.workflow_run.id}/artifacts/${matchingArtifact.id}`; const fileType = target.name.includes('Android') ? 'APK' : 'IPA'; - downloadLink = `[📥 Download ${fileType}](${directLink})`; + + // Format file size + const sizeInMB = (matchingArtifact.size_in_bytes / (1024 * 1024)).toFixed(1); + const sizeInfo = `(${sizeInMB} MB)`; + + // Calculate build duration + let durationInfo = ''; + if (matchingStatus.started_at && matchingStatus.completed_at) { + const durationMs = new Date(matchingStatus.completed_at) - new Date(matchingStatus.started_at); + const durationMin = Math.floor(durationMs / 60000); + const durationSec = Math.floor((durationMs % 60000) / 1000); + durationInfo = ` - ${durationMin}m ${durationSec}s`; + } + + downloadLink = `[📥 Download ${fileType}](${directLink}) ${sizeInfo}${durationInfo}`; } else if (matchingStatus.conclusion === 'failure') { status = `❌ [Failed](${matchingStatus.url})`; downloadLink = '*Build failed*'; @@ -408,7 +439,7 @@ jobs: } } - commentBody += `| ${target.platform} ${target.name.split(' ')[0]} | ${target.device} ${target.name.split(' ')[1]} | ${status} | ${downloadLink} |\n`; + commentBody += `| ${target.platform} ${target.name} | ${target.device} | ${status} | ${downloadLink} |\n`; } commentBody += `\n`; diff --git a/.github/workflows/build-apps.yml b/.github/workflows/build-apps.yml index b300c04d..13905d42 100644 --- a/.github/workflows/build-apps.yml +++ b/.github/workflows/build-apps.yml @@ -41,12 +41,12 @@ jobs: show-progress: false - name: 🍞 Setup Bun - uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version: latest - name: 💾 Cache Bun dependencies - uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: ~/.bun/install/cache key: ${{ runner.os }}-${{ runner.arch }}-bun-develop-${{ hashFiles('bun.lock') }} @@ -60,7 +60,7 @@ jobs: bun run submodule-reload - name: 💾 Cache Gradle global - uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: | ~/.gradle/caches @@ -73,7 +73,7 @@ jobs: run: bun run prebuild - name: 💾 Cache project Gradle (.gradle) - uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: android/.gradle key: ${{ runner.os }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }} @@ -88,7 +88,7 @@ jobs: run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV - name: 📤 Upload APK artifact - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: streamyfin-android-phone-apk-${{ env.DATE_TAG }} path: | @@ -124,12 +124,12 @@ jobs: show-progress: false - name: 🍞 Setup Bun - uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version: latest - name: 💾 Cache Bun dependencies - uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: ~/.bun/install/cache key: ${{ runner.os }}-${{ runner.arch }}-bun-develop-${{ hashFiles('bun.lock') }} @@ -143,7 +143,7 @@ jobs: bun run submodule-reload - name: 💾 Cache Gradle global - uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: | ~/.gradle/caches @@ -156,7 +156,7 @@ jobs: run: bun run prebuild:tv - name: 💾 Cache project Gradle (.gradle) - uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: android/.gradle key: ${{ runner.os }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }} @@ -171,7 +171,7 @@ jobs: run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV - name: 📤 Upload APK artifact - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: streamyfin-android-tv-apk-${{ env.DATE_TAG }} path: | @@ -195,12 +195,12 @@ jobs: show-progress: false - name: 🍞 Setup Bun - uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version: latest - name: 💾 Cache Bun dependencies - uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: ~/.bun/install/cache key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }} @@ -216,12 +216,12 @@ jobs: run: bun run prebuild - name: 🔧 Setup Xcode - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1 + uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1 with: xcode-version: "26.2" - name: 🏗️ Setup EAS - uses: expo/expo-github-action@main + uses: expo/expo-github-action@b184ff86a3c926240f1b6db41764c83a01c02eef # main with: eas-version: latest token: ${{ secrets.EXPO_TOKEN }} @@ -236,7 +236,7 @@ jobs: run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV - name: 📤 Upload IPA artifact - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: streamyfin-ios-phone-ipa-${{ env.DATE_TAG }} path: build-*.ipa @@ -249,6 +249,65 @@ jobs: permissions: contents: read + steps: + - name: 📥 Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + fetch-depth: 0 + submodules: recursive + show-progress: false + + - name: 🍞 Setup Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 + with: + bun-version: latest + + - name: 💾 Cache Bun dependencies + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: ~/.bun/install/cache + key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }} + restore-keys: | + ${{ runner.os }}-bun-cache + + - name: 📦 Install dependencies and reload submodules + run: | + bun install --frozen-lockfile + bun run submodule-reload + + - name: 🛠️ Generate project files + run: bun run prebuild + + - name: 🔧 Setup Xcode + uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1 + with: + xcode-version: "26.2" + + - name: 🚀 Build iOS app + env: + EXPO_TV: 0 + run: bun run ios:unsigned-build ${{ github.event_name == 'pull_request' && '-- --verbose' || '' }} + + - name: 📅 Set date tag + run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV + + - name: 📤 Upload IPA artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: streamyfin-ios-phone-unsigned-ipa-${{ env.DATE_TAG }} + path: build/*.ipa + retention-days: 7 + + build-ios-tv: + # Temporarily disabled until feat/tv-interface is merged (TV UI not ready). + # Re-enable by removing the `false &&` prefix below. + if: false && (!contains(github.event.head_commit.message, '[skip ci]') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'streamyfin/streamyfin')) + runs-on: macos-26 + name: 🍎 Build tvOS IPA + permissions: + contents: read + steps: - name: 📥 Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -277,7 +336,73 @@ jobs: bun run submodule-reload - name: 🛠️ Generate project files - run: bun run prebuild + run: bun run prebuild:tv + + - name: 🔧 Setup Xcode + uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1 + with: + xcode-version: "26.2" + + - name: 🏗️ Setup EAS + uses: expo/expo-github-action@main + with: + eas-version: latest + token: ${{ secrets.EXPO_TOKEN }} + eas-cache: true + + - name: 🚀 Build iOS app + env: + EXPO_TV: 1 + run: eas build -p ios --local --non-interactive + + - name: 📅 Set date tag + run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV + + - name: 📤 Upload IPA artifact + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + with: + name: streamyfin-ios-tv-ipa-${{ env.DATE_TAG }} + path: build-*.ipa + retention-days: 7 + + build-ios-tv-unsigned: + # Temporarily disabled until feat/tv-interface is merged (TV UI not ready). + # Re-enable by removing the `false &&` prefix below. + if: false && (!contains(github.event.head_commit.message, '[skip ci]')) + runs-on: macos-26 + name: 🍎 Build tvOS IPA (Unsigned) + permissions: + contents: read + + steps: + - name: 📥 Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + fetch-depth: 0 + submodules: recursive + show-progress: false + + - name: 🍞 Setup Bun + uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2 + with: + bun-version: latest + + - name: 💾 Cache Bun dependencies + uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 + with: + path: ~/.bun/install/cache + key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }} + restore-keys: | + ${{ runner.os }}-bun-cache + + - name: 📦 Install dependencies and reload submodules + run: | + bun install --frozen-lockfile + bun run submodule-reload + + - name: 🛠️ Generate project files + run: bun run prebuild:tv - name: 🔧 Setup Xcode uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1 @@ -286,8 +411,8 @@ jobs: - name: 🚀 Build iOS app env: - EXPO_TV: 0 - run: bun run ios:unsigned-build ${{ github.event_name == 'pull_request' && '-- --verbose' || '' }} + EXPO_TV: 1 + run: bun run ios:unsigned-build:tv ${{ github.event_name == 'pull_request' && '-- --verbose' || '' }} - name: 📅 Set date tag run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV @@ -295,71 +420,6 @@ jobs: - name: 📤 Upload IPA artifact uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: - name: streamyfin-ios-phone-unsigned-ipa-${{ env.DATE_TAG }} + name: streamyfin-ios-tv-unsigned-ipa-${{ env.DATE_TAG }} path: build/*.ipa retention-days: 7 - - # Disabled for now - uncomment when ready to build iOS TV - # build-ios-tv: - # if: (!contains(github.event.head_commit.message, '[skip ci]') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'streamyfin/streamyfin')) - # runs-on: macos-26 - # name: 🍎 Build iOS IPA (TV) - # permissions: - # contents: read - # - # steps: - # - name: 📥 Checkout code - # uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - # with: - # ref: ${{ github.event.pull_request.head.sha || github.sha }} - # fetch-depth: 0 - # submodules: recursive - # show-progress: false - # - # - name: 🍞 Setup Bun - # uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2 - # with: - # bun-version: latest - # - # - name: 💾 Cache Bun dependencies - # uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 - # with: - # path: ~/.bun/install/cache - # key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }} - # restore-keys: | - # ${{ runner.os }}-bun-cache - # - # - name: 📦 Install dependencies and reload submodules - # run: | - # bun install --frozen-lockfile - # bun run submodule-reload - # - # - name: 🛠️ Generate project files - # run: bun run prebuild:tv - # - # - name: 🔧 Setup Xcode - # uses: maxim-lobanov/setup-xcode@v1 - # with: - # xcode-version: '26.0.1' - # - # - name: 🏗️ Setup EAS - # uses: expo/expo-github-action@main - # with: - # eas-version: latest - # token: ${{ secrets.EXPO_TOKEN }} - # eas-cache: true - # - # - name: 🚀 Build iOS app - # env: - # EXPO_TV: 1 - # run: eas build -p ios --local --non-interactive - # - # - name: 📅 Set date tag - # run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV - # - # - name: 📤 Upload IPA artifact - # uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - # with: - # name: streamyfin-ios-tv-ipa-${{ env.DATE_TAG }} - # path: build-*.ipa - # retention-days: 7 diff --git a/.github/workflows/check-lockfile.yml b/.github/workflows/check-lockfile.yml index ad189f7f..ae4c0fe0 100644 --- a/.github/workflows/check-lockfile.yml +++ b/.github/workflows/check-lockfile.yml @@ -27,12 +27,12 @@ jobs: fetch-depth: 0 - name: 🍞 Setup Bun - uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version: latest - name: 💾 Cache Bun dependencies - uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: | ~/.bun/install/cache diff --git a/.github/workflows/ci-codeql.yml b/.github/workflows/ci-codeql.yml index 29330ac7..e2b52fcf 100644 --- a/.github/workflows/ci-codeql.yml +++ b/.github/workflows/ci-codeql.yml @@ -27,13 +27,13 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: 🏁 Initialize CodeQL - uses: github/codeql-action/init@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0 + uses: github/codeql-action/init@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 with: languages: ${{ matrix.language }} queries: +security-extended,security-and-quality - name: 🛠️ Autobuild - uses: github/codeql-action/autobuild@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0 + uses: github/codeql-action/autobuild@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 - name: 🧪 Perform CodeQL Analysis - uses: github/codeql-action/analyze@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0 + uses: github/codeql-action/analyze@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml index c73cad70..c6effebf 100644 --- a/.github/workflows/crowdin.yml +++ b/.github/workflows/crowdin.yml @@ -28,7 +28,7 @@ jobs: fetch-depth: 0 - name: 🌐 Sync Translations with Crowdin - uses: crowdin/github-action@b4b468cffefb50bdd99dd83e5d2eaeb63c880380 # v2.14.0 + uses: crowdin/github-action@8868a33591d21088edfc398968173a3b98d51706 # v2.16.2 with: upload_sources: true upload_translations: true diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 08e0a884..50013ba2 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -25,7 +25,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4 + - uses: marocchino/sticky-pull-request-comment@0ea0beb66eb9baf113663a64ec522f60e49231c0 # v3.0.4 if: always() && (steps.lint_pr_title.outputs.error_message != null) with: header: pr-title-lint-error @@ -39,7 +39,7 @@ jobs: ``` - if: ${{ steps.lint_pr_title.outputs.error_message == null }} - uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4 + uses: marocchino/sticky-pull-request-comment@0ea0beb66eb9baf113663a64ec522f60e49231c0 # v3.0.4 with: header: pr-title-lint-error delete: true @@ -57,7 +57,7 @@ jobs: fetch-depth: 0 - name: Dependency Review - uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2 + uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 with: fail-on-severity: high base-ref: ${{ github.event.pull_request.base.sha || 'develop' }} @@ -76,7 +76,7 @@ jobs: fetch-depth: 0 - name: 🍞 Setup Bun - uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version: latest @@ -107,12 +107,12 @@ jobs: fetch-depth: 0 - name: "🟢 Setup Node.js" - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: '24.x' - name: "🍞 Setup Bun" - uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version: latest diff --git a/.github/workflows/update-issue-form.yml b/.github/workflows/update-issue-form.yml index 25fa3319..7cc32197 100644 --- a/.github/workflows/update-issue-form.yml +++ b/.github/workflows/update-issue-form.yml @@ -21,14 +21,14 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: "🟢 Setup Node.js" - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: '24.x' cache: 'npm' - name: 🔍 Extract minor version from app.json id: minor - uses: actions/github-script@main + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # main with: result-encoding: string script: | @@ -54,7 +54,7 @@ jobs: dry_run: no-push - name: 📬 Commit and create pull request - uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0 + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: add-paths: .github/ISSUE_TEMPLATE/bug_report.yml branch: ci-update-bug-report diff --git a/app/(auth)/(tabs)/(home)/settings/logs/page.tsx b/app/(auth)/(tabs)/(home)/settings/logs/page.tsx index 87831925..fdd5a2b3 100644 --- a/app/(auth)/(tabs)/(home)/settings/logs/page.tsx +++ b/app/(auth)/(tabs)/(home)/settings/logs/page.tsx @@ -61,7 +61,10 @@ export default function Page() { setLoading(true); try { logsFile.write(JSON.stringify(filteredLogs)); - await Sharing.shareAsync(logsFile.uri, { mimeType: "txt", UTI: "txt" }); + await Sharing.shareAsync(logsFile.uri, { + mimeType: "text/plain", + UTI: "public.plain-text", + }); } catch (e: any) { writeErrorLog("Something went wrong attempting to export", e); } finally { diff --git a/app/(auth)/player/direct-player.tsx b/app/(auth)/player/direct-player.tsx index b5dcac73..a4cffe77 100644 --- a/app/(auth)/player/direct-player.tsx +++ b/app/(auth)/player/direct-player.tsx @@ -48,6 +48,7 @@ import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { OfflineModeProvider } from "@/providers/OfflineModeProvider"; import { useSettings } from "@/utils/atoms/settings"; +import { getPrimaryImageUrl } from "@/utils/jellyfin/image/getPrimaryImageUrl"; import { getStreamUrl } from "@/utils/jellyfin/media/getStreamUrl"; import { getMpvAudioId, @@ -504,6 +505,31 @@ export default function page() { return ticksToSeconds(getInitialPlaybackTicks()); }, [getInitialPlaybackTicks]); + /** Prepare metadata for iOS native media controls (Control Center, Lock Screen) */ + const nowPlayingMetadata = useMemo(() => { + if (!item || !api) return undefined; + + const artworkUri = getPrimaryImageUrl({ + api, + item, + quality: 90, + width: 500, + }); + + return { + title: item.Name || "", + artist: + item.Type === "Episode" + ? item.SeriesName || "" + : item.AlbumArtist || "", + albumTitle: + item.Type === "Episode" && item.SeasonName + ? item.SeasonName + : undefined, + artworkUri: artworkUri || undefined, + }; + }, [item, api]); + /** Build video source config for MPV */ const videoSource = useMemo(() => { if (!stream?.url) return undefined; @@ -932,6 +958,7 @@ export default function page() { ref={videoRef} source={videoSource} style={{ width: "100%", height: "100%" }} + nowPlayingMetadata={nowPlayingMetadata} onProgress={onProgress} onPlaybackStateChange={onPlaybackStateChanged} onLoad={() => setIsVideoLoaded(true)} diff --git a/bun.lock b/bun.lock index 326bd749..43fb9ece 100644 --- a/bun.lock +++ b/bun.lock @@ -50,14 +50,14 @@ "expo-system-ui": "~6.0.9", "expo-task-manager": "14.0.9", "expo-web-browser": "~15.0.10", - "i18next": "^25.0.0", + "i18next": "^26.0.0", "jotai": "2.16.2", "lodash": "4.17.23", "nativewind": "^2.0.11", "patch-package": "^8.0.0", "react": "19.1.0", "react-dom": "19.1.0", - "react-i18next": "16.5.4", + "react-i18next": "17.0.8", "react-native": "0.81.5", "react-native-awesome-slider": "^2.9.0", "react-native-bottom-tabs": "1.1.0", @@ -97,16 +97,16 @@ "devDependencies": { "@babel/core": "7.28.6", "@biomejs/biome": "2.3.11", - "@react-native-community/cli": "20.1.1", - "@react-native-tvos/config-tv": "0.1.4", + "@react-native-community/cli": "20.1.3", + "@react-native-tvos/config-tv": "0.1.6", "@types/jest": "29.5.14", "@types/lodash": "4.17.23", "@types/react": "19.1.17", "@types/react-test-renderer": "19.1.0", "cross-env": "10.1.0", - "expo-doctor": "1.17.14", + "expo-doctor": "1.18.22", "husky": "9.1.7", - "lint-staged": "16.2.7", + "lint-staged": "17.0.5", "react-test-renderer": "19.2.3", "typescript": "5.9.3", }, @@ -404,7 +404,7 @@ "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="], - "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + "@isaacs/cliui": ["@isaacs/cliui@9.0.0", "", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="], "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], @@ -462,6 +462,8 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "@nodable/entities": ["@nodable/entities@2.1.0", "", {}, "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA=="], + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], @@ -512,33 +514,33 @@ "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], - "@react-native-community/cli": ["@react-native-community/cli@20.1.1", "", { "dependencies": { "@react-native-community/cli-clean": "20.1.1", "@react-native-community/cli-config": "20.1.1", "@react-native-community/cli-doctor": "20.1.1", "@react-native-community/cli-server-api": "20.1.1", "@react-native-community/cli-tools": "20.1.1", "@react-native-community/cli-types": "20.1.1", "commander": "^9.4.1", "deepmerge": "^4.3.0", "execa": "^5.0.0", "find-up": "^5.0.0", "fs-extra": "^8.1.0", "graceful-fs": "^4.1.3", "picocolors": "^1.1.1", "prompts": "^2.4.2", "semver": "^7.5.2" }, "bin": { "rnc-cli": "build/bin.js" } }, "sha512-aLPUx43+WSeTOaUepR2FBD5a1V0OAZ1QB2DOlRlW4fOEjtBXgv40eM/ho8g3WCvAOKfPvTvx4fZdcuovTyV81Q=="], + "@react-native-community/cli": ["@react-native-community/cli@20.1.3", "", { "dependencies": { "@react-native-community/cli-clean": "20.1.3", "@react-native-community/cli-config": "20.1.3", "@react-native-community/cli-doctor": "20.1.3", "@react-native-community/cli-server-api": "20.1.3", "@react-native-community/cli-tools": "20.1.3", "@react-native-community/cli-types": "20.1.3", "commander": "^9.4.1", "deepmerge": "^4.3.0", "execa": "^5.0.0", "find-up": "^5.0.0", "fs-extra": "^8.1.0", "graceful-fs": "^4.1.3", "picocolors": "^1.1.1", "prompts": "^2.4.2", "semver": "^7.5.2" }, "bin": { "rnc-cli": "build/bin.js" } }, "sha512-sLo8cu9JyFNfuuF1C+8NJ4DHE/PEFaXGd4enkcxi/OJjGG8+sOQrdjNQ4i+cVh/2c+ah1mEMwsYjc3z0+/MqSg=="], - "@react-native-community/cli-clean": ["@react-native-community/cli-clean@20.1.1", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.1", "execa": "^5.0.0", "fast-glob": "^3.3.2", "picocolors": "^1.1.1" } }, "sha512-6nGQ08w2+EcDwTFC4JFiW/wI2pLwzMrk9thz4um7tKRNW8sADX0IyCsfM2F4rHS720C0UNKYBZE9nAsfp8Vkcw=="], + "@react-native-community/cli-clean": ["@react-native-community/cli-clean@20.1.3", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.3", "execa": "^5.0.0", "fast-glob": "^3.3.2", "picocolors": "^1.1.1" } }, "sha512-sFLdLzapfC0scjgzBJJWYDY2RhHPjuuPkA5r6q0gc/UQH/izXpMpLrhh1DW84cMDraNACK0U62tU7ebNaQ1LMQ=="], - "@react-native-community/cli-config": ["@react-native-community/cli-config@20.1.1", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.1", "cosmiconfig": "^9.0.0", "deepmerge": "^4.3.0", "fast-glob": "^3.3.2", "joi": "^17.2.1", "picocolors": "^1.1.1" } }, "sha512-ajs2i56MANie/v0bMQ1BmRcrOb6MEvLT2rh/I1CA62NXGqF1Rxv6QwsN84LrADMXHRg8QiEMAIADkyDeQHt7Kg=="], + "@react-native-community/cli-config": ["@react-native-community/cli-config@20.1.3", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.3", "cosmiconfig": "^9.0.0", "deepmerge": "^4.3.0", "fast-glob": "^3.3.2", "joi": "^17.2.1", "picocolors": "^1.1.1" } }, "sha512-n73nW0cG92oNF0r994pPqm0DjAShOm3F8LSffDYhJqNAno+h/csmv/37iL4NtSpmKIO8xqsG3uVTXz9X/hzNaQ=="], - "@react-native-community/cli-config-android": ["@react-native-community/cli-config-android@20.1.1", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.1", "fast-glob": "^3.3.2", "fast-xml-parser": "^4.4.1", "picocolors": "^1.1.1" } }, "sha512-1iUV2rPAyoWPo8EceAFC2vZTF+pEd9YqS87c0aqpbGOFE0gs1rHEB+auVR8CdjzftR4U9sq6m2jrdst0rvpIkg=="], + "@react-native-community/cli-config-android": ["@react-native-community/cli-config-android@20.1.3", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.3", "fast-glob": "^3.3.2", "fast-xml-parser": "^5.3.6", "picocolors": "^1.1.1" } }, "sha512-DNHDP+OWLyhKShGciBqPcxhxfp1Z/7GQcb4F+TGyCeKQAr+JdnUjRXN3X+YCU/v+g2kbYYyRJKlGabzkVvdrAw=="], - "@react-native-community/cli-config-apple": ["@react-native-community/cli-config-apple@20.1.1", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.1", "execa": "^5.0.0", "fast-glob": "^3.3.2", "picocolors": "^1.1.1" } }, "sha512-doepJgLJVqeJb5tNoP9hyFIcoZ1OMGO7QN/YMuCCIjbThUQe/J87XdwPol3Qrjr58KRt9xeBVz+kHeW5mtSutw=="], + "@react-native-community/cli-config-apple": ["@react-native-community/cli-config-apple@20.1.3", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.3", "execa": "^5.0.0", "fast-glob": "^3.3.2", "picocolors": "^1.1.1" } }, "sha512-QX9B83nAfCPs0KiaYz61kAEHWr9sttooxzRzNdQwvZTwnsIpvWOT9GvMMj/19OeXiQzMJBzZX0Pgt6+spiUsDQ=="], - "@react-native-community/cli-doctor": ["@react-native-community/cli-doctor@20.1.1", "", { "dependencies": { "@react-native-community/cli-config": "20.1.1", "@react-native-community/cli-platform-android": "20.1.1", "@react-native-community/cli-platform-apple": "20.1.1", "@react-native-community/cli-platform-ios": "20.1.1", "@react-native-community/cli-tools": "20.1.1", "command-exists": "^1.2.8", "deepmerge": "^4.3.0", "envinfo": "^7.13.0", "execa": "^5.0.0", "node-stream-zip": "^1.9.1", "ora": "^5.4.1", "picocolors": "^1.1.1", "semver": "^7.5.2", "wcwidth": "^1.0.1", "yaml": "^2.2.1" } }, "sha512-eFpg5wWnV7uGqvLemshpgj2trPD8cckqxBuI4nT7sxKF/YpA/e3nnnyytHxPP5EnYfWbMcqfaq8hDJoOnJinGQ=="], + "@react-native-community/cli-doctor": ["@react-native-community/cli-doctor@20.1.3", "", { "dependencies": { "@react-native-community/cli-config": "20.1.3", "@react-native-community/cli-platform-android": "20.1.3", "@react-native-community/cli-platform-apple": "20.1.3", "@react-native-community/cli-platform-ios": "20.1.3", "@react-native-community/cli-tools": "20.1.3", "command-exists": "^1.2.8", "deepmerge": "^4.3.0", "envinfo": "^7.13.0", "execa": "^5.0.0", "node-stream-zip": "^1.9.1", "ora": "^5.4.1", "picocolors": "^1.1.1", "semver": "^7.5.2", "wcwidth": "^1.0.1", "yaml": "^2.2.1" } }, "sha512-EI+mAPWn255/WZ4CQohy1I049yiaxVr41C3BeQ2BCyhxODIDR8XRsLzYb1t9MfqK/C3ZncUN2mPSRXFeKPPI1w=="], - "@react-native-community/cli-platform-android": ["@react-native-community/cli-platform-android@20.1.1", "", { "dependencies": { "@react-native-community/cli-config-android": "20.1.1", "@react-native-community/cli-tools": "20.1.1", "execa": "^5.0.0", "logkitty": "^0.7.1", "picocolors": "^1.1.1" } }, "sha512-KPheizJQI0tVvBLy9owzpo+A9qDsDAa87e7a8xNaHnwqGpExnIzFPrbdvrltiZjstU2eB/+/UgNQxYIEd4Oc+g=="], + "@react-native-community/cli-platform-android": ["@react-native-community/cli-platform-android@20.1.3", "", { "dependencies": { "@react-native-community/cli-config-android": "20.1.3", "@react-native-community/cli-tools": "20.1.3", "execa": "^5.0.0", "logkitty": "^0.7.1", "picocolors": "^1.1.1" } }, "sha512-bzB9ELPOISuqgtDZXFPQlkuxx1YFkNx3cNgslc5ElCrk+5LeCLQLIBh/dmIuK8rwUrPcrramjeBj++Noc+TaAA=="], - "@react-native-community/cli-platform-apple": ["@react-native-community/cli-platform-apple@20.1.1", "", { "dependencies": { "@react-native-community/cli-config-apple": "20.1.1", "@react-native-community/cli-tools": "20.1.1", "execa": "^5.0.0", "fast-xml-parser": "^4.4.1", "picocolors": "^1.1.1" } }, "sha512-mQEjOzRFCcQTrCt73Q/+5WWTfUg6U2vLZv5rPuFiNrLbrwRqxVH3OLaXg5gilJkDTJC80z8iOSsdd8MRxONOig=="], + "@react-native-community/cli-platform-apple": ["@react-native-community/cli-platform-apple@20.1.3", "", { "dependencies": { "@react-native-community/cli-config-apple": "20.1.3", "@react-native-community/cli-tools": "20.1.3", "execa": "^5.0.0", "fast-xml-parser": "^5.3.6", "picocolors": "^1.1.1" } }, "sha512-XJ+DqAD4hkplWVXK5AMgN7pP9+4yRSe5KfZ/b42+ofkDBI55ALlUmX+9HWE3fMuRjcotTCoNZqX2ov97cFDXpQ=="], - "@react-native-community/cli-platform-ios": ["@react-native-community/cli-platform-ios@20.1.1", "", { "dependencies": { "@react-native-community/cli-platform-apple": "20.1.1" } }, "sha512-6vr10/oSjKkZO/BBgfFJNQTC/0CDF4WrN8iW9ss+Kt6ZL2QrBXLYz7fobrrboOlHwqqs5EyQadlEaNii7gKRJg=="], + "@react-native-community/cli-platform-ios": ["@react-native-community/cli-platform-ios@20.1.3", "", { "dependencies": { "@react-native-community/cli-platform-apple": "20.1.3" } }, "sha512-2qL48SINotuHbZO73cgqSwqd/OWNx0xTbFSdujhpogV4p8BNwYYypfjh4vJY5qJEB5PxuoVkMXT+aCADpg9nBg=="], - "@react-native-community/cli-server-api": ["@react-native-community/cli-server-api@20.1.1", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.1", "body-parser": "^1.20.3", "compression": "^1.7.1", "connect": "^3.6.5", "errorhandler": "^1.5.1", "nocache": "^3.0.1", "open": "^6.2.0", "pretty-format": "^29.7.0", "serve-static": "^1.13.1", "strict-url-sanitise": "0.0.1", "ws": "^6.2.3" } }, "sha512-phHfiCa4WqfKfaoV2vGVR3ZrYQDQTpI1k+C+i6rXAxFGxPuy8IgFFVOSL543qjKPpHBVwLcA+/xAJCVpdyCtVQ=="], + "@react-native-community/cli-server-api": ["@react-native-community/cli-server-api@20.1.3", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.3", "body-parser": "^2.2.2", "compression": "^1.7.1", "connect": "^3.6.5", "errorhandler": "^1.5.1", "nocache": "^3.0.1", "open": "^6.2.0", "pretty-format": "^29.7.0", "serve-static": "^1.13.1", "strict-url-sanitise": "0.0.1", "ws": "^6.2.3" } }, "sha512-hsNsdUKZDd2T99OuNuiXz4VuvLa1UN0zcxefmPjXQgI0byrBLzzDr+o7p03sKuODSzKi2h+BMnUxiS07HACQLA=="], - "@react-native-community/cli-tools": ["@react-native-community/cli-tools@20.1.1", "", { "dependencies": { "@vscode/sudo-prompt": "^9.0.0", "appdirsjs": "^1.2.4", "execa": "^5.0.0", "find-up": "^5.0.0", "launch-editor": "^2.9.1", "mime": "^2.4.1", "ora": "^5.4.1", "picocolors": "^1.1.1", "prompts": "^2.4.2", "semver": "^7.5.2" } }, "sha512-j+zX/H2X+6ZGneIDj56tZ1Hbnip5nSfnq7yGlMyF/zm3U1hKp3G1jN5v0YEfnz/zEmjr7zruh4Y06KmZrF1lrA=="], + "@react-native-community/cli-tools": ["@react-native-community/cli-tools@20.1.3", "", { "dependencies": { "@vscode/sudo-prompt": "^9.0.0", "appdirsjs": "^1.2.4", "execa": "^5.0.0", "find-up": "^5.0.0", "launch-editor": "^2.9.1", "mime": "^2.4.1", "ora": "^5.4.1", "picocolors": "^1.1.1", "prompts": "^2.4.2", "semver": "^7.5.2" } }, "sha512-EAn0vPCMxtHhfWk2UwLmSUfPfLUnFgC7NjiVJVTKJyVk5qGnkPfoT8te/1IUXFTysUB0F0RIi+NgDB4usFOLeA=="], - "@react-native-community/cli-types": ["@react-native-community/cli-types@20.1.1", "", { "dependencies": { "joi": "^17.2.1" } }, "sha512-Tp+s27I/RDONrGvWVj4IzEmga2HhJhXi8ZlZTfycMMyAcv4LG/CTPira+BUZs8nzLAJNrlJ79pVVPJPqQAe+aw=="], + "@react-native-community/cli-types": ["@react-native-community/cli-types@20.1.3", "", { "dependencies": { "joi": "^17.2.1" } }, "sha512-IdAcegf0pH1hVraxWTG1ACLkYC0LDQfqtaEf42ESyLIF3Xap70JzL/9tAlxw7lSCPZPFWhrcgU0TBc4SkC/ecw=="], "@react-native-community/netinfo": ["@react-native-community/netinfo@11.4.1", "", { "peerDependencies": { "react-native": ">=0.59" } }, "sha512-B0BYAkghz3Q2V09BF88RA601XursIEA111tnc2JOaN7axJWmNefmfjZqw/KdSxKZp7CZUuPpjBmz/WCR9uaHYg=="], - "@react-native-tvos/config-tv": ["@react-native-tvos/config-tv@0.1.4", "", { "dependencies": { "getenv": "^1.0.0" }, "peerDependencies": { "expo": ">=52.0.0" } }, "sha512-xfVDqSFjEUsb+xcMk0hE2Z/M6QZH0QzAJOSQZwo7W/ZRaLrd+xFQnx0LaXqt3kxlR3P7wskKHByDP/FSoUZnbA=="], + "@react-native-tvos/config-tv": ["@react-native-tvos/config-tv@0.1.6", "", { "dependencies": { "getenv": "^1.0.0", "glob": "^11.0.0" }, "peerDependencies": { "expo": ">=52.0.0" } }, "sha512-VxMSIcro+U1EVb64pYShZsc+uE3HNGhfHppoUhTyGwx9ELQkhWvReRTOI4gpb/qeRWEcT+UbUc9Gd9Zlwm572w=="], "@react-native/assets-registry": ["@react-native/assets-registry@0.81.5", "", {}, "sha512-705B6x/5Kxm1RKRvSv0ADYWm5JOnoiQ1ufW7h8uu2E6G9Of/eE6hP/Ivw3U5jI16ERqZxiKQwk34VJbB0niX9w=="], @@ -774,7 +776,7 @@ "bmp-js": ["bmp-js@0.1.0", "", {}, "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw=="], - "body-parser": ["body-parser@1.20.3", "", { "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } }, "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g=="], + "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], @@ -828,7 +830,7 @@ "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], - "cli-truncate": ["cli-truncate@5.1.1", "", { "dependencies": { "slice-ansi": "^7.1.0", "string-width": "^8.0.0" } }, "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A=="], + "cli-truncate": ["cli-truncate@5.2.0", "", { "dependencies": { "slice-ansi": "^8.0.0", "string-width": "^8.2.0" } }, "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw=="], "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], @@ -844,7 +846,7 @@ "color-string": ["color-string@2.1.2", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-RxmjYxbWemV9gKu4zPgiZagUxbH3RQpEIO77XoSSX0ivgABDZ+h8Zuash/EMFLTI4N9QgFPOJ6JQpPZKFxa+dA=="], - "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], + "colorette": ["colorette@1.4.0", "", {}, "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g=="], "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], @@ -990,7 +992,7 @@ "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], - "eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], + "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], @@ -1030,7 +1032,7 @@ "expo-device": ["expo-device@8.0.10", "", { "dependencies": { "ua-parser-js": "^0.7.33" }, "peerDependencies": { "expo": "*" } }, "sha512-jd5BxjaF7382JkDMaC+P04aXXknB2UhWaVx5WiQKA05ugm/8GH5uaz9P9ckWdMKZGQVVEOC8MHaUADoT26KmFA=="], - "expo-doctor": ["expo-doctor@1.17.14", "", { "bin": { "expo-doctor": "build/index.js" } }, "sha512-+UsXFP5ZTVobDuGS5Du8aKU6O6s2sa49QOdGHdzP8UEjQKH8gPb59uw6hxEQmo6YtVboLwQd13QEdcSolBMvLw=="], + "expo-doctor": ["expo-doctor@1.18.22", "", { "bin": { "expo-doctor": "build/index.js" } }, "sha512-AEGwceidWxyYpWEfIf3XnUvc+FbI3OjjyBaXctuoZg10x9An+utrdRf6go/3UFRAG5EkpMOWgUT0j1TKcYDsSQ=="], "expo-file-system": ["expo-file-system@19.0.21", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-s3DlrDdiscBHtab/6W1osrjGL+C2bvoInPJD7sOwmxfJ5Woynv2oc+Fz1/xVXaE/V7HE/+xrHC/H45tu6lZzzg=="], @@ -1094,7 +1096,9 @@ "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], - "fast-xml-parser": ["fast-xml-parser@4.5.3", "", { "dependencies": { "strnum": "^1.1.1" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig=="], + "fast-xml-builder": ["fast-xml-builder@1.2.0", "", { "dependencies": { "path-expression-matcher": "^1.5.0", "xml-naming": "^0.1.0" } }, "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q=="], + + "fast-xml-parser": ["fast-xml-parser@5.8.0", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.2.0", "path-expression-matcher": "^1.5.0", "strnum": "^2.3.0", "xml-naming": "^0.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-6bIM7fsJxeo3uXv7OncQYsBAMPJ7V16Slahl/6M98C/i2q+vB1+4a0MtrvYwDFEUrwDSbAmeLDRXsOBwrL7yAg=="], "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], @@ -1148,7 +1152,7 @@ "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], - "get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="], + "get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="], "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], @@ -1164,7 +1168,7 @@ "gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="], - "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "glob": ["glob@11.1.0", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="], "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], @@ -1204,9 +1208,9 @@ "hyphenate-style-name": ["hyphenate-style-name@1.1.0", "", {}, "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw=="], - "i18next": ["i18next@25.6.1", "", { "dependencies": { "@babel/runtime": "^7.27.6" }, "peerDependencies": { "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-yUWvdXtalZztmKrKw3yz/AvSP3yKyqIkVPx/wyvoYy9lkLmwzItLxp0iHZLG5hfVQ539Jor4XLO+U+NHIXg7pw=="], + "i18next": ["i18next@26.2.0", "", { "peerDependencies": { "typescript": "^5 || ^6" }, "optionalPeers": ["typescript"] }, "sha512-zwBHldHdTmwN7r6UNc7lC6GWNN+YYg3DrRSeHR5PRRBf5QnJZcYHrQc0uaU26qZeYxR7iFZD+Y315dPnKP47wA=="], - "iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], + "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], @@ -1276,7 +1280,7 @@ "istanbul-lib-instrument": ["istanbul-lib-instrument@5.2.1", "", { "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" } }, "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg=="], - "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + "jackspeak": ["jackspeak@4.2.3", "", { "dependencies": { "@isaacs/cliui": "^9.0.0" } }, "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg=="], "jest-diff": ["jest-diff@29.7.0", "", { "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", "jest-get-type": "^29.6.3", "pretty-format": "^29.7.0" } }, "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw=="], @@ -1370,9 +1374,9 @@ "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], - "lint-staged": ["lint-staged@16.2.7", "", { "dependencies": { "commander": "^14.0.2", "listr2": "^9.0.5", "micromatch": "^4.0.8", "nano-spawn": "^2.0.0", "pidtree": "^0.6.0", "string-argv": "^0.3.2", "yaml": "^2.8.1" }, "bin": { "lint-staged": "bin/lint-staged.js" } }, "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow=="], + "lint-staged": ["lint-staged@17.0.5", "", { "dependencies": { "listr2": "^10.2.1", "picomatch": "^4.0.4", "string-argv": "^0.3.2", "tinyexec": "^1.1.2" }, "optionalDependencies": { "yaml": "^2.8.4" }, "bin": { "lint-staged": "bin/lint-staged.js" } }, "sha512-d12yC+/e8RhBjZtaxZn71FyrgU/P5e+uAPifhCLwdosQZP/zamSdKRWDC30ocVIbzDKiFG1McHc/LUgB92GIPw=="], - "listr2": ["listr2@9.0.5", "", { "dependencies": { "cli-truncate": "^5.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" } }, "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g=="], + "listr2": ["listr2@10.2.1", "", { "dependencies": { "cli-truncate": "^5.2.0", "eventemitter3": "^5.0.4", "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^10.0.0" } }, "sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q=="], "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], @@ -1400,7 +1404,7 @@ "mdn-data": ["mdn-data@2.0.14", "", {}, "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="], - "media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="], + "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], "memoize-one": ["memoize-one@5.2.1", "", {}, "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="], @@ -1448,7 +1452,7 @@ "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], - "minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], @@ -1462,8 +1466,6 @@ "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], - "nano-spawn": ["nano-spawn@2.0.0", "", {}, "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw=="], - "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], "nativewind": ["nativewind@2.0.11", "", { "dependencies": { "@babel/generator": "^7.18.7", "@babel/helper-module-imports": "7.18.6", "@babel/types": "7.19.0", "css-mediaquery": "^0.1.2", "css-to-react-native": "^3.0.0", "micromatch": "^4.0.5", "postcss": "^8.4.12", "postcss-calc": "^8.2.4", "postcss-color-functional-notation": "^4.2.2", "postcss-css-variables": "^0.18.0", "postcss-nested": "^5.0.6", "react-is": "^18.1.0", "use-sync-external-store": "^1.1.0" }, "peerDependencies": { "tailwindcss": "~3" } }, "sha512-qCEXUwKW21RYJ33KRAJl3zXq2bCq82WoI564fI21D/TiqhfmstZOqPN53RF8qK1NDK6PGl56b2xaTxgObEePEg=="], @@ -1546,6 +1548,8 @@ "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + "path-expression-matcher": ["path-expression-matcher@1.5.0", "", {}, "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ=="], + "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], @@ -1558,9 +1562,7 @@ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - - "pidtree": ["pidtree@0.6.0", "", { "bin": { "pidtree": "bin/pidtree.js" } }, "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g=="], + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], "pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="], @@ -1616,7 +1618,7 @@ "qrcode-terminal": ["qrcode-terminal@0.11.0", "", { "bin": { "qrcode-terminal": "./bin/qrcode-terminal.js" } }, "sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ=="], - "qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], + "qs": ["qs@6.15.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw=="], "query-string": ["query-string@7.1.3", "", { "dependencies": { "decode-uri-component": "^0.2.2", "filter-obj": "^1.1.0", "split-on-first": "^1.0.0", "strict-uri-encode": "^2.0.0" } }, "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg=="], @@ -1626,7 +1628,7 @@ "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], - "raw-body": ["raw-body@2.5.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA=="], + "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], @@ -1640,7 +1642,7 @@ "react-freeze": ["react-freeze@1.0.4", "", { "peerDependencies": { "react": ">=17.0.0" } }, "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA=="], - "react-i18next": ["react-i18next@16.5.4", "", { "dependencies": { "@babel/runtime": "^7.28.4", "html-parse-stringify": "^3.0.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "i18next": ">= 25.6.2", "react": ">= 16.8.0", "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-6yj+dcfMncEC21QPhOTsW8mOSO+pzFmT6uvU7XXdvM/Cp38zJkmTeMeKmTrmCMD5ToT79FmiE/mRWiYWcJYW4g=="], + "react-i18next": ["react-i18next@17.0.8", "", { "dependencies": { "@babel/runtime": "^7.29.2", "html-parse-stringify": "^3.0.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "i18next": ">= 26.2.0", "react": ">= 16.8.0", "react-dom": "*", "react-native": "*", "typescript": "^5 || ^6" }, "optionalPeers": ["react-dom", "react-native", "typescript"] }, "sha512-0ooKbGLU8JXhe1zwpQUWIeXSgLPOfwJmgheWRIUpcoA0CpyabpGhayjdG+/eA5esC1AQ8h2jWpXjJfzQzeDOCw=="], "react-is": ["react-is@19.2.3", "", {}, "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA=="], @@ -1696,7 +1698,7 @@ "react-native-text-ticker": ["react-native-text-ticker@1.15.0", "", {}, "sha512-d/uK+PIOhsYMy1r8h825iq/nADiHsabz3WMbRJSnkpQYn+K9aykUAXRRhu8ZbTAzk4CgnUWajJEFxS5ZDygsdg=="], - "react-native-track-player": ["react-native-track-player@github:lovegaoshi/react-native-track-player#003afd0", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-windows": "*", "shaka-player": "^4.7.9" }, "optionalPeers": ["react-native-windows", "shaka-player"] }, "lovegaoshi-react-native-track-player-003afd0"], + "react-native-track-player": ["react-native-track-player@github:lovegaoshi/react-native-track-player#003afd0", { "peerDependencies": { "react": "*", "react-native": "*", "react-native-windows": "*", "shaka-player": "^4.7.9" }, "optionalPeers": ["react-native-windows", "shaka-player"] }, "lovegaoshi-react-native-track-player-003afd0", "sha512-HR7BaMDMBhQ4xAy5XeQEkT0fBosWw2x9+X2QOD4buocxuX03D770LaRKm5rgQ/qDzchr92KW7+d8fISI14fRLA=="], "react-native-udp": ["react-native-udp@4.1.7", "", { "dependencies": { "buffer": "^5.6.0", "events": "^3.1.0" } }, "sha512-NUE3zewu61NCdSsLlj+l0ad6qojcVEZPT4hVG/x6DU9U4iCzwtfZSASh9vm7teAcVzLkdD+cO3411LHshAi/wA=="], @@ -1826,7 +1828,7 @@ "slash": ["slash@2.0.0", "", {}, "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A=="], - "slice-ansi": ["slice-ansi@7.1.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w=="], + "slice-ansi": ["slice-ansi@8.0.0", "", { "dependencies": { "ansi-styles": "^6.2.3", "is-fullwidth-code-point": "^5.1.0" } }, "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg=="], "slugify": ["slugify@1.6.6", "", {}, "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw=="], @@ -1872,7 +1874,7 @@ "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], - "strnum": ["strnum@1.1.2", "", {}, "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA=="], + "strnum": ["strnum@2.3.0", "", {}, "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q=="], "strtok3": ["strtok3@6.3.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^4.1.0" } }, "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw=="], @@ -1910,6 +1912,8 @@ "tinycolor2": ["tinycolor2@1.6.0", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="], + "tinyexec": ["tinyexec@1.1.2", "", {}, "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA=="], + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], "tmp": ["tmp@0.2.5", "", {}, "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow=="], @@ -1934,7 +1938,7 @@ "type-fest": ["type-fest@0.7.1", "", {}, "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg=="], - "type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="], + "type-is": ["type-is@2.1.0", "", { "dependencies": { "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], @@ -2014,7 +2018,7 @@ "wonka": ["wonka@6.3.5", "", {}, "sha512-SSil+ecw6B4/Dm7Pf2sAshKQ5hWFvfyGlfPbEd6A14dOH6VDjrmbY86u6nZvy9omGwwIPFR8V41+of1EezgoUw=="], - "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], + "wrap-ansi": ["wrap-ansi@10.0.0", "", { "dependencies": { "ansi-styles": "^6.2.3", "string-width": "^8.2.0", "strip-ansi": "^7.1.2" } }, "sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ=="], "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], @@ -2026,6 +2030,8 @@ "xcode": ["xcode@3.0.1", "", { "dependencies": { "simple-plist": "^1.1.0", "uuid": "^7.0.3" } }, "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA=="], + "xml-naming": ["xml-naming@0.1.0", "", {}, "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw=="], + "xml2js": ["xml2js@0.6.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w=="], "xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="], @@ -2034,7 +2040,7 @@ "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - "yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="], + "yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], @@ -2118,6 +2124,8 @@ "@expo/cli/glob": ["glob@13.0.0", "", { "dependencies": { "minimatch": "^10.1.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA=="], + "@expo/cli/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@expo/cli/ora": ["ora@3.4.0", "", { "dependencies": { "chalk": "^2.4.2", "cli-cursor": "^2.1.0", "cli-spinners": "^2.0.0", "log-symbols": "^2.2.0", "strip-ansi": "^5.2.0", "wcwidth": "^1.0.1" } }, "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg=="], "@expo/cli/picomatch": ["picomatch@3.0.1", "", {}, "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag=="], @@ -2154,6 +2162,8 @@ "@expo/fingerprint/glob": ["glob@13.0.0", "", { "dependencies": { "minimatch": "^10.1.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA=="], + "@expo/fingerprint/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@expo/fingerprint/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], "@expo/image-utils/getenv": ["getenv@2.0.0", "", {}, "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ=="], @@ -2172,6 +2182,8 @@ "@expo/metro-config/glob": ["glob@13.0.0", "", { "dependencies": { "minimatch": "^10.1.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA=="], + "@expo/metro-config/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@expo/metro-config/postcss": ["postcss@8.4.49", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA=="], "@expo/package-manager/ora": ["ora@3.4.0", "", { "dependencies": { "chalk": "^2.4.2", "cli-cursor": "^2.1.0", "cli-spinners": "^2.0.0", "log-symbols": "^2.2.0", "strip-ansi": "^5.2.0", "wcwidth": "^1.0.1" } }, "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg=="], @@ -2180,12 +2192,6 @@ "@expo/xcpretty/@babel/code-frame": ["@babel/code-frame@7.10.4", "", { "dependencies": { "@babel/highlight": "^7.10.4" } }, "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg=="], - "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], - - "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], - - "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - "@istanbuljs/load-nyc-config/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], "@istanbuljs/load-nyc-config/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], @@ -2222,6 +2228,8 @@ "@react-native/codegen/@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], + "@react-native/codegen/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "@react-native/community-cli-plugin/metro": ["metro@0.83.2", "", { "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/parser": "^7.25.3", "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.3", "@babel/types": "^7.25.2", "accepts": "^1.3.7", "chalk": "^4.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", "debug": "^4.4.0", "error-stack-parser": "^2.0.6", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "hermes-parser": "0.32.0", "image-size": "^1.0.2", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", "metro-babel-transformer": "0.83.2", "metro-cache": "0.83.2", "metro-cache-key": "0.83.2", "metro-config": "0.83.2", "metro-core": "0.83.2", "metro-file-map": "0.83.2", "metro-resolver": "0.83.2", "metro-runtime": "0.83.2", "metro-source-map": "0.83.2", "metro-symbolicate": "0.83.2", "metro-transform-plugins": "0.83.2", "metro-transform-worker": "0.83.2", "mime-types": "^2.1.27", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", "source-map": "^0.5.6", "throat": "^5.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": { "metro": "src/cli.js" } }, "sha512-HQgs9H1FyVbRptNSMy/ImchTTE5vS2MSqLoOo7hbDoBq6hPPZokwJvBMwrYSxdjQZmLXz2JFZtdvS+ZfgTc9yw=="], "@react-native/community-cli-plugin/metro-config": ["metro-config@0.83.2", "", { "dependencies": { "connect": "^3.6.5", "flow-enums-runtime": "^0.0.6", "jest-validate": "^29.7.0", "metro": "0.83.2", "metro-cache": "0.83.2", "metro-core": "0.83.2", "metro-runtime": "0.83.2", "yaml": "^2.6.1" } }, "sha512-1FjCcdBe3e3D08gSSiU9u3Vtxd7alGH3x/DNFqWDFf5NouX4kLgbVloDDClr1UrLz62c0fHh2Vfr9ecmrOZp+g=="], @@ -2260,12 +2268,12 @@ "accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], - "ansi-fragments/colorette": ["colorette@1.4.0", "", {}, "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g=="], - "ansi-fragments/slice-ansi": ["slice-ansi@2.1.0", "", { "dependencies": { "ansi-styles": "^3.2.0", "astral-regex": "^1.0.0", "is-fullwidth-code-point": "^2.0.0" } }, "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ=="], "ansi-fragments/strip-ansi": ["strip-ansi@5.2.0", "", { "dependencies": { "ansi-regex": "^4.1.0" } }, "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA=="], + "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "babel-jest/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], "babel-plugin-jest-hoist/@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], @@ -2280,13 +2288,11 @@ "better-opn/open": ["open@8.4.2", "", { "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" } }, "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ=="], - "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - "cli-truncate/string-width": ["string-width@8.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" } }, "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg=="], + "cli-truncate/string-width": ["string-width@8.2.1", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA=="], "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], @@ -2322,8 +2328,6 @@ "foreground-child/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - "glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], - "hoist-non-react-statics/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], "hosted-git-info/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -2340,16 +2344,20 @@ "jest-message-util/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + "jest-util/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], "lighthouse-logger/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "lint-staged/commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="], - "log-update/cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="], + "log-update/slice-ansi": ["slice-ansi@7.1.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w=="], + "log-update/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + "log-update/wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], + "logkitty/yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="], "metro/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], @@ -2376,6 +2384,8 @@ "metro-babel-transformer/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], + "metro-config/yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="], + "metro-source-map/@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="], "metro-source-map/@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], @@ -2396,6 +2406,8 @@ "metro-transform-worker/@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "nativewind/@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="], "nativewind/@babel/types": ["@babel/types@7.19.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.18.10", "@babel/helper-validator-identifier": "^7.18.6", "to-fast-properties": "^2.0.0" } }, "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA=="], @@ -2412,22 +2424,32 @@ "patch-package/semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="], + "patch-package/yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="], + "path-scurry/lru-cache": ["lru-cache@11.2.4", "", {}, "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg=="], "postcss-css-variables/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], "postcss-load-config/lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], + "postcss-load-config/yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="], + "pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + "raw-body/http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], + "react-devtools-core/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], "react-dom/scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], + "react-i18next/@babel/runtime": ["@babel/runtime@7.29.2", "", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="], + "react-native/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + "react-native/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "react-native/scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], "react-native/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], @@ -2442,8 +2464,12 @@ "readable-web-to-node-stream/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], + "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "requireg/resolve": ["resolve@1.7.1", "", { "dependencies": { "path-parse": "^1.0.5" } }, "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw=="], + "rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "send/mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], @@ -2472,15 +2498,21 @@ "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + "test-exclude/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "test-exclude/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], "tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], + + "type-is/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], + "whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - "wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], + "wrap-ansi/string-width": ["string-width@8.2.1", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA=="], "wrap-ansi/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], @@ -2640,10 +2672,6 @@ "@expo/cli/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "@expo/config-plugins/glob/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], - - "@expo/config/glob/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], - "@expo/config/sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], "@expo/fingerprint/glob/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], @@ -2676,12 +2704,6 @@ "@expo/package-manager/ora/strip-ansi": ["strip-ansi@5.2.0", "", { "dependencies": { "ansi-regex": "^4.1.0" } }, "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA=="], - "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], - - "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], - - "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - "@istanbuljs/load-nyc-config/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], "@istanbuljs/load-nyc-config/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], @@ -2756,6 +2778,8 @@ "@react-native/codegen/@babel/parser/@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], + "@react-native/codegen/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + "@react-native/community-cli-plugin/metro/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], "@react-native/community-cli-plugin/metro/@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="], @@ -2800,6 +2824,8 @@ "@react-native/community-cli-plugin/metro-config/metro-runtime": ["metro-runtime@0.83.2", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-nnsPtgRvFbNKwemqs0FuyFDzXLl+ezuFsUXDbX8o0SXOfsOPijqiQrf3kuafO1Zx1aUWf4NOrKJMAQP5EEHg9A=="], + "@react-native/community-cli-plugin/metro-config/yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="], + "@react-native/community-cli-plugin/metro-core/metro-resolver": ["metro-resolver@0.83.2", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-Yf5mjyuiRE/Y+KvqfsZxrbHDA15NZxyfg8pIk0qg47LfAJhpMVEX+36e6ZRBq7KVBqy6VDX5Sq55iHGM4xSm7Q=="], "@react-navigation/bottom-tabs/color/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], @@ -2832,8 +2858,6 @@ "babel-preset-expo/@babel/helper-module-imports/@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], - "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "chalk/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "cli-truncate/string-width/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], @@ -2860,8 +2884,6 @@ "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], - "istanbul-lib-instrument/@babel/core/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], "istanbul-lib-instrument/@babel/core/@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="], @@ -2884,8 +2906,16 @@ "log-update/cli-cursor/restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], + "log-update/slice-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "log-update/slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@5.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.1" } }, "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ=="], + "log-update/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + "log-update/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "log-update/wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], + "logkitty/yargs/cliui": ["cliui@6.0.0", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ=="], "logkitty/yargs/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], @@ -2980,8 +3010,14 @@ "patch-package/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + "raw-body/http-errors/statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + + "react-native/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + "readable-web-to-node-stream/readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + "rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "serve-static/send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], @@ -2990,15 +3026,21 @@ "serve-static/send/mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], + "slice-ansi/is-fullwidth-code-point/get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="], + + "sucrase/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + + "sucrase/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "sucrase/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], "terminal-link/ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], "test-exclude/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], - "wrap-ansi-cjs/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + "type-is/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], - "wrap-ansi/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + "wrap-ansi-cjs/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], @@ -3082,6 +3124,8 @@ "@react-native/codegen/@babel/core/@babel/helper-module-transforms/@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], + "@react-native/codegen/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + "@react-native/community-cli-plugin/metro/@babel/core/@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], "@react-native/community-cli-plugin/metro/@babel/core/@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="], @@ -3130,8 +3174,6 @@ "expo-manifests/@expo/config/@expo/config-plugins/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], - "expo-manifests/@expo/config/glob/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], - "expo-manifests/@expo/config/sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], "istanbul-lib-instrument/@babel/core/@babel/helper-compilation-targets/@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="], @@ -3142,6 +3184,12 @@ "log-update/cli-cursor/restore-cursor/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "log-update/slice-ansi/is-fullwidth-code-point/get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="], + + "log-update/wrap-ansi/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + + "log-update/wrap-ansi/string-width/get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="], + "logkitty/yargs/cliui/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], "logkitty/yargs/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], @@ -3164,8 +3212,14 @@ "metro/@babel/core/@babel/helper-module-transforms/@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], + "react-native/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + "serve-static/send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "sucrase/glob/jackspeak/@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + "sucrase/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "wrap-ansi-cjs/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], @@ -3200,6 +3254,12 @@ "logkitty/yargs/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + "sucrase/glob/jackspeak/@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "sucrase/glob/jackspeak/@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "sucrase/glob/jackspeak/@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + "@expo/cli/ora/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], "@expo/cli/ora/cli-cursor/restore-cursor/onetime/mimic-fn": ["mimic-fn@1.2.0", "", {}, "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="], @@ -3212,6 +3272,12 @@ "logkitty/yargs/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + "sucrase/glob/jackspeak/@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "sucrase/glob/jackspeak/@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "sucrase/glob/jackspeak/@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + "logkitty/yargs/cliui/wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], } } diff --git a/modules/mpv-player/android/src/main/java/expo/modules/mpvplayer/MpvPlayerModule.kt b/modules/mpv-player/android/src/main/java/expo/modules/mpvplayer/MpvPlayerModule.kt index 245c4ef5..1735c14c 100644 --- a/modules/mpv-player/android/src/main/java/expo/modules/mpvplayer/MpvPlayerModule.kt +++ b/modules/mpv-player/android/src/main/java/expo/modules/mpvplayer/MpvPlayerModule.kt @@ -43,6 +43,12 @@ class MpvPlayerModule : Module() { view.loadVideo(config) } + // Now Playing metadata for media controls (iOS-only, no-op on Android) + // Android handles media session differently via MediaSessionCompat + Prop("nowPlayingMetadata") { _: MpvPlayerView, _: Map? -> + // No-op on Android - media session integration would require MediaSessionCompat + } + // Async function to play video AsyncFunction("play") { view: MpvPlayerView -> view.play() diff --git a/modules/mpv-player/ios/MPVLayerRenderer.swift b/modules/mpv-player/ios/MPVLayerRenderer.swift index e2c4573a..e6686a81 100644 --- a/modules/mpv-player/ios/MPVLayerRenderer.swift +++ b/modules/mpv-player/ios/MPVLayerRenderer.swift @@ -10,6 +10,7 @@ protocol MPVLayerRendererDelegate: AnyObject { func renderer(_ renderer: MPVLayerRenderer, didChangeLoading isLoading: Bool) func renderer(_ renderer: MPVLayerRenderer, didBecomeReadyToSeek: Bool) func renderer(_ renderer: MPVLayerRenderer, didBecomeTracksReady: Bool) + func renderer(_ renderer: MPVLayerRenderer, didSelectAudioOutput audioOutput: String) } /// MPV player using vo_avfoundation for video output. @@ -170,7 +171,11 @@ final class MPVLayerRenderer { // Enable composite OSD mode - renders subtitles directly onto video frames using GPU // This is better for PiP as subtitles are baked into the video // NOTE: Must be set BEFORE the #if targetEnvironment check or tvOS will freeze on player exit + #if targetEnvironment(simulator) + checkError(mpv_set_option_string(handle, "avfoundation-composite-osd", "no")) + #else checkError(mpv_set_option_string(handle, "avfoundation-composite-osd", "yes")) + #endif // Hardware decoding with VideoToolbox // On simulator, use software decoding since VideoToolbox is not available @@ -347,7 +352,8 @@ final class MPVLayerRenderer { ("pause", MPV_FORMAT_FLAG), ("track-list/count", MPV_FORMAT_INT64), ("paused-for-cache", MPV_FORMAT_FLAG), - ("demuxer-cache-duration", MPV_FORMAT_DOUBLE) + ("demuxer-cache-duration", MPV_FORMAT_DOUBLE), + ("current-ao", MPV_FORMAT_STRING) ] for (name, format) in properties { mpv_observe_property(handle, 0, name, format) @@ -552,6 +558,15 @@ final class MPVLayerRenderer { self.delegate?.renderer(self, didBecomeTracksReady: true) } } + case "current-ao": + // Audio output is now active - notify delegate + if let aoName = getStringProperty(handle: handle, name: name) { + print("[MPV] 🔊 Audio output selected: \(aoName)") + DispatchQueue.main.async { [weak self] in + guard let self else { return } + self.delegate?.renderer(self, didSelectAudioOutput: aoName) + } + } default: break } diff --git a/modules/mpv-player/ios/MPVNowPlayingManager.swift b/modules/mpv-player/ios/MPVNowPlayingManager.swift new file mode 100644 index 00000000..73dafdbc --- /dev/null +++ b/modules/mpv-player/ios/MPVNowPlayingManager.swift @@ -0,0 +1,188 @@ +import Foundation +import MediaPlayer +import UIKit +import AVFoundation + +/// Simple manager for Now Playing info and remote commands. +/// Stores all state internally and updates Now Playing when ready. +class MPVNowPlayingManager { + static let shared = MPVNowPlayingManager() + + // State + private var title: String? + private var artist: String? + private var albumTitle: String? + private var cachedArtwork: MPMediaItemArtwork? + private var duration: TimeInterval = 0 + private var position: TimeInterval = 0 + private var isPlaying: Bool = false + private var isCommandsSetup = false + + private var artworkTask: URLSessionDataTask? + + private init() {} + + // MARK: - Audio Session + + func activateAudioSession() { + do { + let session = AVAudioSession.sharedInstance() + try session.setCategory(.playback, mode: .moviePlayback) + try session.setActive(true) + print("[NowPlaying] Audio session activated") + } catch { + print("[NowPlaying] Audio session error: \(error)") + } + } + + func deactivateAudioSession() { + do { + try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation) + print("[NowPlaying] Audio session deactivated") + } catch { + print("[NowPlaying] Deactivation error: \(error)") + } + } + + // MARK: - Remote Commands + + func setupRemoteCommands( + playHandler: @escaping () -> Void, + pauseHandler: @escaping () -> Void, + toggleHandler: @escaping () -> Void, + seekHandler: @escaping (TimeInterval) -> Void, + skipForward: @escaping (TimeInterval) -> Void, + skipBackward: @escaping (TimeInterval) -> Void + ) { + guard !isCommandsSetup else { return } + isCommandsSetup = true + + DispatchQueue.main.async { + UIApplication.shared.beginReceivingRemoteControlEvents() + } + + let cc = MPRemoteCommandCenter.shared() + + cc.playCommand.isEnabled = true + cc.playCommand.addTarget { _ in playHandler(); return .success } + + cc.pauseCommand.isEnabled = true + cc.pauseCommand.addTarget { _ in pauseHandler(); return .success } + + cc.togglePlayPauseCommand.isEnabled = true + cc.togglePlayPauseCommand.addTarget { _ in toggleHandler(); return .success } + + cc.skipForwardCommand.isEnabled = true + cc.skipForwardCommand.preferredIntervals = [15] + cc.skipForwardCommand.addTarget { e in + if let ev = e as? MPSkipIntervalCommandEvent { skipForward(ev.interval) } + return .success + } + + cc.skipBackwardCommand.isEnabled = true + cc.skipBackwardCommand.preferredIntervals = [15] + cc.skipBackwardCommand.addTarget { e in + if let ev = e as? MPSkipIntervalCommandEvent { skipBackward(ev.interval) } + return .success + } + + cc.changePlaybackPositionCommand.isEnabled = true + cc.changePlaybackPositionCommand.addTarget { e in + if let ev = e as? MPChangePlaybackPositionCommandEvent { seekHandler(ev.positionTime) } + return .success + } + + print("[NowPlaying] Remote commands ready") + } + + func cleanupRemoteCommands() { + guard isCommandsSetup else { return } + + let cc = MPRemoteCommandCenter.shared() + cc.playCommand.removeTarget(nil) + cc.pauseCommand.removeTarget(nil) + cc.togglePlayPauseCommand.removeTarget(nil) + cc.skipForwardCommand.removeTarget(nil) + cc.skipBackwardCommand.removeTarget(nil) + cc.changePlaybackPositionCommand.removeTarget(nil) + + DispatchQueue.main.async { + UIApplication.shared.endReceivingRemoteControlEvents() + } + + isCommandsSetup = false + print("[NowPlaying] Remote commands cleaned up") + } + + // MARK: - State Updates (call these whenever data changes) + + /// Set metadata (title, artist, artwork URL) + func setMetadata(title: String?, artist: String?, albumTitle: String?, artworkUrl: String?) { + self.title = title + self.artist = artist + self.albumTitle = albumTitle + + print("[NowPlaying] Metadata: \(title ?? "nil")") + + // Load artwork async + artworkTask?.cancel() + if let urlString = artworkUrl, let url = URL(string: urlString) { + artworkTask = URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in + if let data = data, let image = UIImage(data: data) { + self?.cachedArtwork = MPMediaItemArtwork(boundsSize: image.size) { _ in image } + print("[NowPlaying] Artwork loaded") + DispatchQueue.main.async { self?.refresh() } + } + } + artworkTask?.resume() + } + + refresh() + } + + /// Update playback state (position, duration, playing) + func updatePlayback(position: TimeInterval, duration: TimeInterval, isPlaying: Bool) { + self.position = position + self.duration = duration + self.isPlaying = isPlaying + refresh() + } + + /// Clear everything + func clear() { + artworkTask?.cancel() + title = nil + artist = nil + albumTitle = nil + cachedArtwork = nil + duration = 0 + position = 0 + isPlaying = false + MPNowPlayingInfoCenter.default().nowPlayingInfo = nil + print("[NowPlaying] Cleared") + } + + // MARK: - Private + + /// Refresh Now Playing info if we have enough data + private func refresh() { + guard duration > 0 else { + print("[NowPlaying] refresh skipped - duration is 0") + return + } + + var info: [String: Any] = [ + MPMediaItemPropertyPlaybackDuration: duration, + MPNowPlayingInfoPropertyElapsedPlaybackTime: position, + MPNowPlayingInfoPropertyPlaybackRate: isPlaying ? 1.0 : 0.0 + ] + + if let title { info[MPMediaItemPropertyTitle] = title } + if let artist { info[MPMediaItemPropertyArtist] = artist } + if let albumTitle { info[MPMediaItemPropertyAlbumTitle] = albumTitle } + if let cachedArtwork { info[MPMediaItemPropertyArtwork] = cachedArtwork } + + MPNowPlayingInfoCenter.default().nowPlayingInfo = info + print("[NowPlaying] ✅ Set info: title=\(title ?? "nil"), dur=\(Int(duration))s, pos=\(Int(position))s, rate=\(isPlaying ? 1.0 : 0.0)") + } +} diff --git a/modules/mpv-player/ios/MpvPlayerModule.swift b/modules/mpv-player/ios/MpvPlayerModule.swift index b60a3d40..feaf27f6 100644 --- a/modules/mpv-player/ios/MpvPlayerModule.swift +++ b/modules/mpv-player/ios/MpvPlayerModule.swift @@ -43,6 +43,21 @@ public class MpvPlayerModule: Module { view.loadVideo(config: config) } + // Now Playing metadata for iOS Control Center and Lock Screen + Prop("nowPlayingMetadata") { (view: MpvPlayerView, metadata: [String: Any]?) in + guard let metadata = metadata else { return } + // Convert Any values to String, filtering out nil/null values + var stringMetadata: [String: String] = [:] + for (key, value) in metadata { + if let stringValue = value as? String { + stringMetadata[key] = stringValue + } + } + if !stringMetadata.isEmpty { + view.setNowPlayingMetadata(stringMetadata) + } + } + // Async function to play video AsyncFunction("play") { (view: MpvPlayerView) in view.play() diff --git a/modules/mpv-player/ios/MpvPlayerView.swift b/modules/mpv-player/ios/MpvPlayerView.swift index 89502a9a..35e0d19b 100644 --- a/modules/mpv-player/ios/MpvPlayerView.swift +++ b/modules/mpv-player/ios/MpvPlayerView.swift @@ -1,6 +1,7 @@ import AVFoundation import CoreMedia import ExpoModulesCore +import MediaPlayer import UIKit /// Configuration for loading a video @@ -41,7 +42,6 @@ class MpvPlayerView: ExpoView { private var renderer: MPVLayerRenderer? private var videoContainer: UIView! private var pipController: PiPController? - let onLoad = EventDispatcher() let onPlaybackStateChange = EventDispatcher() let onProgress = EventDispatcher() @@ -53,11 +53,14 @@ class MpvPlayerView: ExpoView { private var cachedDuration: Double = 0 private var intendedPlayState: Bool = false private var _isZoomedToFill: Bool = false + + // Reference to now playing manager + private let nowPlayingManager = MPVNowPlayingManager.shared required init(appContext: AppContext? = nil) { super.init(appContext: appContext) + setupNotifications() setupView() - // Note: Decoder reset is handled automatically via KVO in MPVLayerRenderer } private func setupView() { @@ -109,6 +112,77 @@ class MpvPlayerView: ExpoView { CATransaction.commit() } + // MARK: - Audio Session & Notifications + + private func setupNotifications() { + // Handle audio session interruptions (e.g., incoming calls, other apps playing audio) + NotificationCenter.default.addObserver( + self, selector: #selector(handleAudioSessionInterruption), + name: AVAudioSession.interruptionNotification, object: nil) + } + + @objc func handleAudioSessionInterruption(_ notification: Notification) { + guard let userInfo = notification.userInfo, + let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt, + let type = AVAudioSession.InterruptionType(rawValue: typeValue) else { + return + } + + switch type { + case .began: + // Interruption began - pause the video + print("[MPV] Audio session interrupted - pausing video") + self.pause() + + case .ended: + // Interruption ended - check if we should resume + if let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt { + let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue) + if options.contains(.shouldResume) { + print("[MPV] Audio session interruption ended - can resume") + // Don't auto-resume - let user manually resume playback + } else { + print("[MPV] Audio session interruption ended - should not resume") + } + } + + @unknown default: + break + } + } + + private func setupRemoteCommands() { + nowPlayingManager.setupRemoteCommands( + playHandler: { [weak self] in self?.play() }, + pauseHandler: { [weak self] in self?.pause() }, + toggleHandler: { [weak self] in + guard let self else { return } + if self.intendedPlayState { self.pause() } else { self.play() } + }, + seekHandler: { [weak self] time in self?.seekTo(position: time) }, + skipForward: { [weak self] interval in self?.seekBy(offset: interval) }, + skipBackward: { [weak self] interval in self?.seekBy(offset: -interval) } + ) + } + + // MARK: - Now Playing Info + + func setNowPlayingMetadata(_ metadata: [String: String]) { + print("[MPV] setNowPlayingMetadata: \(metadata["title"] ?? "nil")") + nowPlayingManager.setMetadata( + title: metadata["title"], + artist: metadata["artist"], + albumTitle: metadata["albumTitle"], + artworkUrl: metadata["artworkUri"] + ) + } + + private func clearNowPlayingInfo() { + nowPlayingManager.cleanupRemoteCommands() + nowPlayingManager.deactivateAudioSession() + nowPlayingManager.clear() + } + func loadVideo(config: VideoLoadConfig) { // Skip reload if same URL is already playing if currentURL == config.url { @@ -149,6 +223,7 @@ class MpvPlayerView: ExpoView { func play() { intendedPlayState = true + setupRemoteCommands() renderer?.play() pipController?.setPlaybackRate(1.0) pipController?.updatePlaybackState() @@ -162,10 +237,17 @@ class MpvPlayerView: ExpoView { } func seekTo(position: Double) { + // Update cached position and Now Playing immediately for smooth Control Center feedback + cachedPosition = position + syncNowPlaying(isPlaying: !isPaused()) renderer?.seek(to: position) } func seekBy(offset: Double) { + // Update cached position and Now Playing immediately for smooth Control Center feedback + let newPosition = max(0, min(cachedPosition + offset, cachedDuration)) + cachedPosition = newPosition + syncNowPlaying(isPlaying: !isPaused()) renderer?.seek(by: offset) } @@ -292,23 +374,32 @@ class MpvPlayerView: ExpoView { pipController?.stopPictureInPicture() renderer?.stop() displayLayer.removeFromSuperlayer() + clearNowPlayingInfo() + NotificationCenter.default.removeObserver(self) } } // MARK: - MPVLayerRendererDelegate extension MpvPlayerView: MPVLayerRendererDelegate { + + // MARK: - Single location for Now Playing updates + private func syncNowPlaying(isPlaying: Bool) { + print("[MPV] syncNowPlaying: pos=\(Int(cachedPosition))s, dur=\(Int(cachedDuration))s, playing=\(isPlaying)") + nowPlayingManager.updatePlayback(position: cachedPosition, duration: cachedDuration, isPlaying: isPlaying) + } + func renderer(_: MPVLayerRenderer, didUpdatePosition position: Double, duration: Double, cacheSeconds: Double) { cachedPosition = position cachedDuration = duration DispatchQueue.main.async { [weak self] in guard let self else { return } - // Update PiP current time for progress bar + if self.pipController?.isPictureInPictureActive == true { self.pipController?.setCurrentTimeFromSeconds(position, duration: duration) } - + self.onProgress([ "position": position, "duration": duration, @@ -321,12 +412,10 @@ extension MpvPlayerView: MPVLayerRendererDelegate { func renderer(_: MPVLayerRenderer, didChangePause isPaused: Bool) { DispatchQueue.main.async { [weak self] in guard let self else { return } - // Don't update intendedPlayState here - it's only set by user actions (play/pause) - // This prevents PiP UI flicker during seeking - // Sync timebase rate with actual playback state + print("[MPV] didChangePause: isPaused=\(isPaused), cachedDuration=\(self.cachedDuration)") self.pipController?.setPlaybackRate(isPaused ? 0.0 : 1.0) - + self.syncNowPlaying(isPlaying: !isPaused) self.onPlaybackStateChange([ "isPaused": isPaused, "isPlaying": !isPaused, @@ -358,6 +447,13 @@ extension MpvPlayerView: MPVLayerRendererDelegate { self.onTracksReady([:]) } } + + func renderer(_: MPVLayerRenderer, didSelectAudioOutput audioOutput: String) { + // Audio output is now active - this is the right time to activate audio session and set Now Playing + print("[MPV] Audio output ready (\(audioOutput)), activating audio session and syncing Now Playing") + nowPlayingManager.activateAudioSession() + syncNowPlaying(isPlaying: !isPaused()) + } } // MARK: - PiPControllerDelegate diff --git a/modules/mpv-player/src/MpvPlayer.types.ts b/modules/mpv-player/src/MpvPlayer.types.ts index 23f86093..8f42c8d9 100644 --- a/modules/mpv-player/src/MpvPlayer.types.ts +++ b/modules/mpv-player/src/MpvPlayer.types.ts @@ -25,6 +25,13 @@ export type OnErrorEventPayload = { export type OnTracksReadyEventPayload = Record; +export type NowPlayingMetadata = { + title?: string; + artist?: string; + albumTitle?: string; + artworkUri?: string; +}; + export type MpvPlayerModuleEvents = { onChange: (params: ChangeEventPayload) => void; }; @@ -48,6 +55,8 @@ export type VideoSource = { export type MpvPlayerViewProps = { source?: VideoSource; style?: StyleProp; + /** Metadata for iOS Control Center and Lock Screen now playing info */ + nowPlayingMetadata?: NowPlayingMetadata; onLoad?: (event: { nativeEvent: OnLoadEventPayload }) => void; onPlaybackStateChange?: (event: { nativeEvent: OnPlaybackStateChangePayload; diff --git a/package.json b/package.json index 9864985a..26ff101d 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "android:tv": "cross-env EXPO_TV=1 expo run:android", "build:android:local": "cd android && cross-env NODE_ENV=production ./gradlew assembleRelease", "ios:unsigned-build": "cross-env EXPO_TV=0 bun scripts/ios/build-ios.ts --production", + "ios:unsigned-build:tv": "cross-env EXPO_TV=1 bun scripts/ios/build-ios.ts --production", "prepare": "husky", "typecheck": "node scripts/typecheck.js", "check": "biome check . --max-diagnostics 1000", @@ -70,14 +71,14 @@ "expo-system-ui": "~6.0.9", "expo-task-manager": "14.0.9", "expo-web-browser": "~15.0.10", - "i18next": "^25.0.0", + "i18next": "^26.0.0", "jotai": "2.16.2", "lodash": "4.17.23", "nativewind": "^2.0.11", "patch-package": "^8.0.0", "react": "19.1.0", "react-dom": "19.1.0", - "react-i18next": "16.5.4", + "react-i18next": "17.0.8", "react-native": "0.81.5", "react-native-awesome-slider": "^2.9.0", "react-native-bottom-tabs": "1.1.0", @@ -117,16 +118,16 @@ "devDependencies": { "@babel/core": "7.28.6", "@biomejs/biome": "2.3.11", - "@react-native-community/cli": "20.1.1", - "@react-native-tvos/config-tv": "0.1.4", + "@react-native-community/cli": "20.1.3", + "@react-native-tvos/config-tv": "0.1.6", "@types/jest": "29.5.14", "@types/lodash": "4.17.23", "@types/react": "19.1.17", "@types/react-test-renderer": "19.1.0", "cross-env": "10.1.0", - "expo-doctor": "1.17.14", + "expo-doctor": "1.18.22", "husky": "9.1.7", - "lint-staged": "16.2.7", + "lint-staged": "17.0.5", "react-test-renderer": "19.2.3", "typescript": "5.9.3" }, diff --git a/providers/GlobalModalProvider.tsx b/providers/GlobalModalProvider.tsx index 76ced95a..c2268899 100644 --- a/providers/GlobalModalProvider.tsx +++ b/providers/GlobalModalProvider.tsx @@ -5,10 +5,13 @@ import { type ReactNode, useCallback, useContext, + useEffect, useRef, useState, } from "react"; +import { BackHandler, Platform } from "react-native"; + interface ModalOptions { enableDynamicSizing?: boolean; snapPoints?: (string | number)[]; @@ -73,6 +76,25 @@ export const GlobalModalProvider: React.FC = ({ }); }, []); + useEffect(() => { + if (Platform.OS !== "android") return; + + const onBackPress = () => { + if (isVisible) { + hideModal(); + return true; + } + return false; + }; + + const subscription = BackHandler.addEventListener( + "hardwareBackPress", + onBackPress, + ); + + return () => subscription.remove(); + }, [isVisible, hideModal]); + const value = { showModal, hideModal, diff --git a/translations/de.json b/translations/de.json index bfb614b7..3d3001dc 100644 --- a/translations/de.json +++ b/translations/de.json @@ -7,7 +7,7 @@ "username_placeholder": "Benutzername", "password_placeholder": "Passwort", "login_button": "Anmelden", - "quick_connect": "Schnellverbindung", + "quick_connect": "Quick Connect", "enter_code_to_login": "Gib den Code {{code}} ein, um dich anzumelden", "failed_to_initiate_quick_connect": "Fehler beim Initiieren der Schnellverbindung", "got_it": "Verstanden", @@ -30,48 +30,48 @@ "connect_button": "Verbinden", "previous_servers": "Vorherige Server", "clear_button": "Löschen", - "swipe_to_remove": "Swipe to remove", + "swipe_to_remove": "Wischen, um zu entfernen", "search_for_local_servers": "Nach lokalen Servern suchen", "searching": "Suche...", "servers": "Server", - "saved": "Saved", - "session_expired": "Session Expired", - "please_login_again": "Your saved session has expired. Please log in again.", - "remove_saved_login": "Remove Saved Login", - "remove_saved_login_description": "This will remove your saved credentials for this server. You'll need to enter your username and password again next time.", - "accounts_count": "{{count}} accounts", - "select_account": "Select Account", - "add_account": "Add Account", - "remove_account_description": "This will remove the saved credentials for {{username}}." + "saved": "Gespeichert", + "session_expired": "Sitzung abgelaufen", + "please_login_again": "Ihre Sitzung ist abgelaufen. Bitte erneut anmelden.", + "remove_saved_login": "Gespeicherte Zugangsdaten entfernen", + "remove_saved_login_description": "Hiermit werden ihre gespeicherten Zugangsdaten für diesen Server entfernt. Sie müssen sich dann erneut anmelden.", + "accounts_count": "{{count}} Konten", + "select_account": "Konto auswählen", + "add_account": "Konto hinzufügen", + "remove_account_description": "Hiermit werden die gespeicherten Zugangsdaten für {{username}} entfernt." }, "save_account": { - "title": "Save Account", - "save_for_later": "Save this account", - "security_option": "Security Option", - "no_protection": "No protection", - "no_protection_desc": "Quick login without authentication", - "pin_code": "PIN code", - "pin_code_desc": "4-digit PIN required when switching", - "password": "Re-enter password", - "password_desc": "Password required when switching", - "save_button": "Save", - "cancel_button": "Cancel" + "title": "Konto speichern", + "save_for_later": "Dieses Konto speichern", + "security_option": "Sicherheitseinstellung", + "no_protection": "Keine", + "no_protection_desc": "Schnellanmeldung ohne Authentifizierung", + "pin_code": "PIN", + "pin_code_desc": "4-stellige PIN bei Konto-Wechsel erforderlich", + "password": "Passwort wiederholen", + "password_desc": "Passwort bei Konto-Wechsel erforderlich", + "save_button": "Speichern", + "cancel_button": "Abbrechen" }, "pin": { - "enter_pin": "Enter PIN", - "enter_pin_for": "Enter PIN for {{username}}", - "enter_4_digits": "Enter 4 digits", - "invalid_pin": "Invalid PIN", - "setup_pin": "Set Up PIN", - "confirm_pin": "Confirm PIN", - "pins_dont_match": "PINs don't match", - "forgot_pin": "Forgot PIN?", - "forgot_pin_desc": "Your saved credentials will be removed" + "enter_pin": "PIN eingeben", + "enter_pin_for": "PIN für {{username}} eingeben", + "enter_4_digits": "4 Ziffern eingeben", + "invalid_pin": "Ungültige PIN", + "setup_pin": "PIN festlegen", + "confirm_pin": "PIN bestätigen", + "pins_dont_match": "PIN stimmt nicht überein", + "forgot_pin": "PIN vergessen?", + "forgot_pin_desc": "Ihre gespeicherten Zugangsdaten werden entfernt" }, "password": { - "enter_password": "Enter Password", - "enter_password_for": "Enter password for {{username}}", - "invalid_password": "Invalid password" + "enter_password": "Passwort eingeben", + "enter_password_for": "Passwort für {{username}} eingeben", + "invalid_password": "Ungültiges Passwort" }, "home": { "checking_server_connection": "Überprüfe Serververbindung...", @@ -87,7 +87,7 @@ "error_message": "Etwas ist schiefgelaufen.\nBitte melde dich ab und wieder an.", "continue_watching": "Weiterschauen", "next_up": "Als nächstes", - "continue_and_next_up": "Continue & Next Up", + "continue_and_next_up": "\"Weiterschauen\" und \"Als Nächstes\"", "recently_added_in": "Kürzlich hinzugefügt in {{libraryName}}", "suggested_movies": "Empfohlene Filme", "suggested_episodes": "Empfohlene Episoden", @@ -120,36 +120,36 @@ }, "appearance": { "title": "Aussehen", - "merge_next_up_continue_watching": "Merge Continue Watching & Next Up", - "hide_remote_session_button": "Hide Remote Session Button" + "merge_next_up_continue_watching": "\"Weiterschauen\" und \"Als Nächstes\" kombinieren", + "hide_remote_session_button": "Button für Remote-Sitzung ausblenden" }, "network": { - "title": "Network", - "local_network": "Local Network", - "auto_switch_enabled": "Auto-switch when at home", - "auto_switch_description": "Automatically switch to local URL when connected to home WiFi", - "local_url": "Local URL", - "local_url_hint": "Enter your local server address (e.g., http://192.168.1.100:8096)", + "title": "Netzwerk", + "local_network": "Lokales Netzwerk", + "auto_switch_enabled": "Zuhause automatisch wechseln", + "auto_switch_description": "Im WLAN Zuhause automatisch zu lokaler URL wechseln", + "local_url": "Lokale URL", + "local_url_hint": "Lokale Server-URL eingeben (zB. http://192.168.1.100:8096)", "local_url_placeholder": "http://192.168.1.100:8096", - "home_wifi_networks": "Home WiFi Networks", - "add_current_network": "Add \"{{ssid}}\"", - "not_connected_to_wifi": "Not connected to WiFi", - "no_networks_configured": "No networks configured", - "add_network_hint": "Add your home WiFi network to enable auto-switching", - "current_wifi": "Current WiFi", - "using_url": "Using", - "local": "Local URL", + "home_wifi_networks": "Private WLAN-Netze", + "add_current_network": "{{ssid}} hinzufügen", + "not_connected_to_wifi": "Nicht mit WLAN verbunden", + "no_networks_configured": "Keine Netzwerke konfiguriert", + "add_network_hint": "Füge dein privates WLAN-Netz hinzu um automatischen Wechsel zu aktivieren", + "current_wifi": "Aktuelles WLAN-Netz", + "using_url": "Verwendet", + "local": "Lokale URL", "remote": "Remote URL", - "not_connected": "Not connected", - "current_server": "Current Server", + "not_connected": "Nicht verbunden", + "current_server": "Aktueller Server", "remote_url": "Remote URL", - "active_url": "Active URL", - "not_configured": "Not configured", - "network_added": "Network added", - "network_already_added": "Network already added", - "no_wifi_connected": "Not connected to WiFi", - "permission_denied": "Location permission denied", - "permission_denied_explanation": "Location permission is required to detect WiFi network for auto-switching. Please enable it in Settings." + "active_url": "Aktive URL", + "not_configured": "Nicht konfiguriert", + "network_added": "Netzwerk hinzugefügt", + "network_already_added": "Netzwerk bereits hinzugefügt", + "no_wifi_connected": "Nicht mit WLAN verbunden", + "permission_denied": "Standortberechtigung nicht verfügbar", + "permission_denied_explanation": "Standortberechtigung ist nötig um WLAN-Netze für den automatischen Wechsel zu erkennen. Bitte in den Einstellungen aktivieren." }, "user_info": { "user_info_title": "Benutzerinformationen", @@ -159,82 +159,82 @@ "app_version": "App-Version" }, "quick_connect": { - "quick_connect_title": "Schnellverbindung", - "authorize_button": "Schnellverbindung autorisieren", - "enter_the_quick_connect_code": "Gib den Schnellverbindungscode ein...", - "success": "Erfolg", - "quick_connect_autorized": "Schnellverbindung autorisiert", + "quick_connect_title": "Quick Connect", + "authorize_button": "Quick Connect autorisieren", + "enter_the_quick_connect_code": "Quick Connect-Code eingeben...", + "success": "Erfolgreich verbunden", + "quick_connect_autorized": "Quick Connect autorisiert", "error": "Fehler", "invalid_code": "Ungültiger Code", "authorize": "Autorisieren" }, "media_controls": { "media_controls_title": "Mediensteuerung", - "forward_skip_length": "Vorspulzeit", - "rewind_length": "Rückspulzeit", + "forward_skip_length": "Vorspullänge", + "rewind_length": "Rückspullänge", "seconds_unit": "s" }, "gesture_controls": { "gesture_controls_title": "Gestensteuerung", - "horizontal_swipe_skip": "Horizontales Wischen zum Überspringen", - "horizontal_swipe_skip_description": "Wische links/rechts, wenn Steuerelemente ausgeblendet werden um zu überspringen", - "left_side_brightness": "Helligkeitskontrolle der linken Seite", - "left_side_brightness_description": "Wischen Sie auf der linken Seite nach oben/runter, um die Helligkeit anzupassen", - "right_side_volume": "Lautstärkeregelung der rechten Seite", - "right_side_volume_description": "Auf der rechten Seite nach oben/unten wischen, um Lautstärke anzupassen", - "hide_volume_slider": "Hide Volume Slider", - "hide_volume_slider_description": "Hide the volume slider in the video player", - "hide_brightness_slider": "Hide Brightness Slider", - "hide_brightness_slider_description": "Hide the brightness slider in the video player" + "horizontal_swipe_skip": "Horizontal Wischen zum Überspringen", + "horizontal_swipe_skip_description": "Wische links/rechts, wenn Steuerelemente ausgeblendet sind um zu überspringen", + "left_side_brightness": "Helligkeitsregler Links", + "left_side_brightness_description": "Links nach oben/unten wischen um Helligkeit anzupassen", + "right_side_volume": "Lautstärkeregler Rechts", + "right_side_volume_description": "Rechts nach oben/unten wischen um Lautstärke anzupassen", + "hide_volume_slider": "Lautstärkeregler ausblenden", + "hide_volume_slider_description": "Lautstärkeregler im Videoplayer ausblenden", + "hide_brightness_slider": "Helligkeitsregler ausblenden", + "hide_brightness_slider_description": "Helligkeitsregler im Videoplayer ausblenden" }, "audio": { "audio_title": "Audio", - "set_audio_track": "Audiospur aus dem vorherigen Element festlegen", + "set_audio_track": "Audiospur aus dem vorherigen Element übernehmen", "audio_language": "Audio-Sprache", - "audio_hint": "Wähl die Standardsprache für Audio aus.", + "audio_hint": "Standardsprache für Audio auswählen.", "none": "Keine", "language": "Sprache", "transcode_mode": { - "title": "Audio Transcoding", - "description": "Controls how surround audio (7.1, TrueHD, DTS-HD) is handled", + "title": "Audio-Transcoding", + "description": "Legt fest, wie Surround-Audio (7.1, TrueHD, DTS-HD) behandelt wird", "auto": "Auto", - "stereo": "Force Stereo", - "5_1": "Allow 5.1", + "stereo": "Stereo erzwingen", + "5_1": "5.1 erlauben", "passthrough": "Passthrough" } }, "subtitles": { "subtitle_title": "Untertitel", - "subtitle_hint": "Konfigurier die Untertitel-Präferenzen.", + "subtitle_hint": "Untertitel-Erscheinungsbild und Verhalten konfigurieren.", "subtitle_language": "Untertitel-Sprache", "subtitle_mode": "Untertitel-Modus", - "set_subtitle_track": "Untertitel-Spur aus dem vorherigen Element festlegen", + "set_subtitle_track": "Untertitel-Spur aus dem vorherigen Element übernehmen", "subtitle_size": "Untertitel-Größe", "none": "Keine", "language": "Sprache", "loading": "Lädt", "modes": { "Default": "Standard", - "Smart": "Intelligent", + "Smart": "Smart", "Always": "Immer", "None": "Keine", - "OnlyForced": "Nur erzwungen" + "OnlyForced": "Nur erzwungene" }, "text_color": "Textfarbe", "background_color": "Hintergrundfarbe", "outline_color": "Konturfarbe", - "outline_thickness": "Umriss Dicke", + "outline_thickness": "Konturdicke", "background_opacity": "Hintergrundtransparenz", - "outline_opacity": "Kontur-Deckkraft", - "bold_text": "Bold Text", + "outline_opacity": "Konturtransparenz", + "bold_text": "Fettgedruckter Text", "colors": { "Black": "Schwarz", "Gray": "Grau", "Silver": "Silber", "White": "Weiß", - "Maroon": "Marotte", + "Maroon": "Rotbraun", "Red": "Rot", - "Fuchsia": "Fuchsia", + "Fuchsia": "Magenta", "Yellow": "Gelb", "Olive": "Olivgrün", "Green": "Grün", @@ -251,29 +251,29 @@ "Normal": "Normal", "Thick": "Dick" }, - "subtitle_color": "Subtitle Color", - "subtitle_background_color": "Background Color", - "subtitle_font": "Subtitle Font", - "ksplayer_title": "KSPlayer Settings", + "subtitle_color": "Untertitelfarbe", + "subtitle_background_color": "Hintergrundfarbe", + "subtitle_font": "Untertitel-Schriftart", + "ksplayer_title": "KSPlayer Einstellungen", "hardware_decode": "Hardware Decoding", - "hardware_decode_description": "Use hardware acceleration for video decoding. Disable if you experience playback issues." + "hardware_decode_description": "Hardwarebeschleunigung für Video Decoding verwenden. Deaktivieren wenn Wiedergabeprobleme auftreten." }, "vlc_subtitles": { - "title": "VLC Subtitle Settings", - "hint": "Customize subtitle appearance for VLC player. Changes take effect on next playback.", - "text_color": "Text Color", - "background_color": "Background Color", - "background_opacity": "Background Opacity", - "outline_color": "Outline Color", - "outline_opacity": "Outline Opacity", - "outline_thickness": "Outline Thickness", - "bold": "Bold Text", - "margin": "Bottom Margin" + "title": "VLC Untertitel-Einstellungen", + "hint": "Anpassen des Untertitel-Erscheinungsbildes für VLC. Änderungen werden bei der nächsten Wiedergabe übernommen.", + "text_color": "Schriftfarbe", + "background_color": "Hintergrundfarbe", + "background_opacity": "Hintergrundtransparenz", + "outline_color": "Konturfarbe", + "outline_opacity": "Konturtransparenz", + "outline_thickness": "Konturdicke", + "bold": "Fettgedruckter Text", + "margin": "Unterer Abstand" }, "video_player": { - "title": "Video Player", - "video_player": "Video Player", - "video_player_description": "Choose which video player to use on iOS.", + "title": "Videoplayer", + "video_player": "Videoplayer", + "video_player_description": "Videoplayer auf iOS auswählen.", "ksplayer": "KSPlayer", "vlc": "VLC" }, @@ -282,7 +282,7 @@ "video_orientation": "Videoausrichtung", "orientation": "Ausrichtung", "orientations": { - "DEFAULT": "Standard", + "DEFAULT": "Geräteausrichtung folgen", "ALL": "Alle", "PORTRAIT": "Hochformat", "PORTRAIT_UP": "Hochformat oben", @@ -294,54 +294,54 @@ "UNKNOWN": "Unbekannt" }, "safe_area_in_controls": "Sicherer Bereich in den Steuerungen", - "video_player": "Video player", + "video_player": "Videoplayer", "video_players": { "VLC_3": "VLC 3", "VLC_4": "VLC 4 (Experimentell + PiP)" }, "show_custom_menu_links": "Benutzerdefinierte Menülinks anzeigen", - "show_large_home_carousel": "Zeige Großes Heimkarussell (Beta)", + "show_large_home_carousel": "Zeige große Startseiten-Übersicht (Beta)", "hide_libraries": "Bibliotheken ausblenden", - "select_liraries_you_want_to_hide": "Wähl die Bibliotheken aus, die du im Bibliothekstab und auf der Startseite ausblenden möchtest.", + "select_liraries_you_want_to_hide": "Bibliotheken auswählen die aus dem Bibliothekstab und der Startseite ausgeblendet werden sollen.", "disable_haptic_feedback": "Haptisches Feedback deaktivieren", "default_quality": "Standardqualität", - "default_playback_speed": "Default Playback Speed", - "auto_play_next_episode": "Auto-play Next Episode", - "max_auto_play_episode_count": "Max. automatische Wiedergabe Episodenanzahl", + "default_playback_speed": "Standard-Wiedergabegeschwindigkeit", + "auto_play_next_episode": "Automatisch nächste Episode abspielen", + "max_auto_play_episode_count": "Maximale automatisch abzuspielende Episodenanzahl", "disabled": "Deaktiviert" }, "downloads": { "downloads_title": "Downloads" }, "music": { - "title": "Music", - "playback_title": "Playback", - "playback_description": "Configure how music is played.", - "prefer_downloaded": "Prefer Downloaded Songs", + "title": "Musik", + "playback_title": "Wiedergabe", + "playback_description": "Konfigurieren, wie Musik abgespielt wird.", + "prefer_downloaded": "Bevorzuge heruntergeladene Titel", "caching_title": "Caching", - "caching_description": "Automatically cache upcoming tracks for smoother playback.", - "lookahead_enabled": "Enable Look-Ahead Caching", - "lookahead_count": "Tracks to Pre-cache", - "max_cache_size": "Max Cache Size" + "caching_description": "Automatisches Caching anstehender Titel für bessere Wiedergabe.", + "lookahead_enabled": "Look-Ahead Caching aktivieren", + "lookahead_count": "Titel vorher in den Cache laden", + "max_cache_size": "Maximale Cache-Größe" }, "plugins": { - "plugins_title": "Erweiterungen", + "plugins_title": "Plugins", "jellyseerr": { - "jellyseerr_warning": "Diese integration ist in einer frühen Entwicklungsphase. Erwarte Veränderungen.", - "server_url": "Server Adresse", - "server_url_hint": "Beispiel: http(s)://your-host.url\n(Portnummer hinzufügen, falls erforderlich)", - "server_url_placeholder": "Jellyseerr URL...", + "jellyseerr_warning": "Diese Integration ist in einer frühen Entwicklungsphase und kann jederzeit geändert werden.", + "server_url": "Server URL", + "server_url_hint": "Beispiel: http(s)://your-host.url\n(Port hinzufügen, falls erforderlich)", + "server_url_placeholder": "Seerr URL", "password": "Passwort", "password_placeholder": "Passwort für Jellyfin Benutzer {{username}} eingeben", "login_button": "Anmelden", "total_media_requests": "Gesamtanfragen", "movie_quota_limit": "Film-Anfragelimit", - "movie_quota_days": "Film-Anfragetage", - "tv_quota_limit": "TV-Anfragelimit", - "tv_quota_days": "TV-Anfragetage", - "reset_jellyseerr_config_button": "Setze Jellyseerr-Konfiguration zurück", + "movie_quota_days": "Film-Anfragetagelimit", + "tv_quota_limit": "Serien-Anfragelimit", + "tv_quota_days": "Serien-Anfragetagelimit", + "reset_jellyseerr_config_button": "Seerr-Konfiguration zurücksetzen", "unlimited": "Unlimitiert", - "plus_n_more": "+{{n}} more", + "plus_n_more": "+{{n}} weitere", "order_by": { "DEFAULT": "Standard", "VOTE_COUNT_AND_AVERAGE": "Stimmenanzahl und Durchschnitt", @@ -352,71 +352,71 @@ "enable_marlin_search": "Aktiviere Marlin Search", "url": "URL", "server_url_placeholder": "http(s)://domain.org:port", - "marlin_search_hint": "Gib die URL für den Marlin Server ein. Die URL sollte http oder https enthalten und optional den Port.", + "marlin_search_hint": "URL für den Marlin Server eingeben. Die URL sollte http oder https enthalten und optional den Port.", "read_more_about_marlin": "Erfahre mehr über Marlin.", "save_button": "Speichern", "toasts": { "saved": "Gespeichert", - "refreshed": "Settings refreshed from server" + "refreshed": "Einstellungen vom Server aktualisiert" }, - "refresh_from_server": "Refresh Settings from Server" + "refresh_from_server": "Einstellungen vom Server aktualisieren" }, "streamystats": { - "enable_streamystats": "Enable Streamystats", - "disable_streamystats": "Disable Streamystats", - "enable_search": "Use for Search", + "enable_streamystats": "Streamystats aktivieren", + "disable_streamystats": "Streamystats deaktivieren", + "enable_search": "Zum Suchen verwenden", "url": "URL", "server_url_placeholder": "http(s)://streamystats.example.com", - "streamystats_search_hint": "Enter the URL for your Streamystats server. The URL should include http or https and optionally the port.", - "read_more_about_streamystats": "Read More About Streamystats.", - "save_button": "Save", - "save": "Save", + "streamystats_search_hint": "URL für den Streamystats-Server eingeben.", + "read_more_about_streamystats": "Mehr über Streamystats erfahren.", + "save_button": "Speichern", + "save": "Gespeichert", "features_title": "Features", - "home_sections_title": "Home Sections", - "enable_movie_recommendations": "Movie Recommendations", - "enable_series_recommendations": "Series Recommendations", - "enable_promoted_watchlists": "Promoted Watchlists", - "hide_watchlists_tab": "Hide Watchlists Tab", - "home_sections_hint": "Show personalized recommendations and promoted watchlists from Streamystats on the home page.", - "recommended_movies": "Recommended Movies", - "recommended_series": "Recommended Series", + "home_sections_title": "Startseitenbereiche", + "enable_movie_recommendations": "Filmempfehlungen", + "enable_series_recommendations": "Serienempfehlungen", + "enable_promoted_watchlists": "Empfohlene Merklisten", + "hide_watchlists_tab": "Merklisten-Tab ausblenden", + "home_sections_hint": "Zeige personalisierte Empfehlungen und empfohlene Merklisten von Streamystats auf der Startseite.", + "recommended_movies": "Empfohlene Filme", + "recommended_series": "Empfohlene Serien", "toasts": { - "saved": "Saved", - "refreshed": "Settings refreshed from server", - "disabled": "Streamystats disabled" + "saved": "Gespeichert", + "refreshed": "Einstellungen vom Server aktualisiert", + "disabled": "Streamystats deaktiviert" }, - "refresh_from_server": "Refresh Settings from Server" + "refresh_from_server": "Einstellungen vom Server aktualisieren" }, "kefinTweaks": { - "watchlist_enabler": "Enable our Watchlist integration", - "watchlist_button": "Toggle Watchlist integration" + "watchlist_enabler": "Merklisten-Integration aktivieren", + "watchlist_button": "Merklisten-Integration umschalten" } }, "storage": { "storage_title": "Speicher", "app_usage": "App {{usedSpace}}%", "device_usage": "Gerät {{availableSpace}}%", - "size_used": "{{used}} von {{total}} benutzt", - "delete_all_downloaded_files": "Alle Downloads löschen", - "music_cache_title": "Music Cache", - "music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support", - "enable_music_cache": "Enable Music Cache", - "clear_music_cache": "Clear Music Cache", - "music_cache_size": "{{size}} cached", - "music_cache_cleared": "Music cache cleared", - "delete_all_downloaded_songs": "Delete All Downloaded Songs", - "downloaded_songs_size": "{{size}} downloaded", - "downloaded_songs_deleted": "Downloaded songs deleted" + "size_used": "{{used}} von {{total}} genutzt", + "delete_all_downloaded_files": "Alle heruntergeladenen Dateien löschen", + "music_cache_title": "Musik-Cache", + "music_cache_description": "Beim Anhören Titel automatisch in den Cache laden um bessere Wiedergabe und Offline-Wiedergabe zu ermöglichen", + "enable_music_cache": "Musik-Cache aktivieren", + "clear_music_cache": "Musik-Cache leeren", + "music_cache_size": "{{size}} gechached", + "music_cache_cleared": "Musik-Cache geleert", + "delete_all_downloaded_songs": "Alle heruntergeladenen Titel löschen", + "downloaded_songs_size": "{{size}} heruntergeladen", + "downloaded_songs_deleted": "Heruntergeladene Titel gelöscht" }, "intro": { - "title": "Intro ", - "show_intro": "Show intro", - "reset_intro": "Reset intro" + "title": "Einführung", + "show_intro": "Einführung anzeigen", + "reset_intro": "Einführung zurücksetzen" }, "logs": { "logs_title": "Logs", - "export_logs": "Export logs", - "click_for_more_info": "Click for more info", + "export_logs": "Logs exportieren", + "click_for_more_info": "Für mehr Informationen klicken", "level": "Level", "no_logs_available": "Keine Logs verfügbar", "delete_all_logs": "Alle Logs löschen" @@ -438,21 +438,21 @@ }, "downloads": { "downloads_title": "Downloads", - "tvseries": "TV-Serien", + "tvseries": "Serien", "movies": "Filme", "queue": "Warteschlange", "other_media": "Andere Medien", - "queue_hint": "Warteschlange und aktive Downloads gehen verloren bei App-Neustart", + "queue_hint": "Warteschlange und aktive Downloads gehen verloren wenn die App neu gestartet wird", "no_items_in_queue": "Keine Elemente in der Warteschlange", "no_downloaded_items": "Keine heruntergeladenen Elemente", "delete_all_movies_button": "Alle Filme löschen", - "delete_all_tvseries_button": "Alle TV-Serien löschen", + "delete_all_tvseries_button": "Alle Serien löschen", "delete_all_button": "Alles löschen", - "delete_all_other_media_button": "Andere Medien löschen", + "delete_all_other_media_button": "Alle anderen Medien löschen", "active_download": "Aktiver Download", "no_active_downloads": "Keine aktiven Downloads", "active_downloads": "Aktive Downloads", - "new_app_version_requires_re_download": "Die neue App-Version erfordert das erneute Herunterladen.", + "new_app_version_requires_re_download": "Neue App-Version erfordert erneutes Herunterladen", "new_app_version_requires_re_download_description": "Die neue App-Version erfordert das erneute Herunterladen von Filmen und Serien. Bitte lösche alle heruntergeladenen Elemente und starte den Download erneut.", "back": "Zurück", "delete": "Löschen", @@ -463,8 +463,8 @@ "you_are_not_allowed_to_download_files": "Du hast keine Berechtigung, Dateien herunterzuladen", "deleted_all_movies_successfully": "Alle Filme erfolgreich gelöscht!", "failed_to_delete_all_movies": "Fehler beim Löschen aller Filme", - "deleted_all_tvseries_successfully": "Alle TV-Serien erfolgreich gelöscht!", - "failed_to_delete_all_tvseries": "Fehler beim Löschen aller TV-Serien", + "deleted_all_tvseries_successfully": "Alle Serien erfolgreich gelöscht!", + "failed_to_delete_all_tvseries": "Fehler beim Löschen aller Serien", "deleted_media_successfully": "Andere Medien erfolgreich gelöscht!", "failed_to_delete_media": "Fehler beim Löschen anderer Medien", "download_deleted": "Download gelöscht", @@ -486,7 +486,7 @@ "all_files_folders_and_jobs_deleted_successfully": "Alle Dateien, Ordner und Jobs erfolgreich gelöscht", "failed_to_clean_cache_directory": "Fehler beim Bereinigen des Cache-Verzeichnisses", "could_not_get_download_url_for_item": "Download-URL für {{itemName}} konnte nicht geladen werden", - "go_to_downloads": "Gehe zu den Downloads", + "go_to_downloads": "Zu Downloads gehen", "file_deleted": "{{item}} gelöscht" } } @@ -499,18 +499,18 @@ "subtitle": "Untertitel", "play": "Abspielen", "none": "Keine", - "track": "Track", - "cancel": "Cancel", - "delete": "Delete", + "track": "Spur", + "cancel": "Abbrechen", + "delete": "Löschen", "ok": "OK", - "remove": "Remove", - "next": "Next", - "back": "Back", - "continue": "Continue", - "verifying": "Verifying..." + "remove": "Entfernen", + "next": "Weiter", + "back": "Zurück", + "continue": "Fortsetzen", + "verifying": "Verifiziere..." }, "search": { - "search": "Suche...", + "search": "Suchen...", "x_items": "{{count}} Elemente", "library": "Bibliothek", "discover": "Entdecken", @@ -521,33 +521,33 @@ "episodes": "Episoden", "collections": "Sammlungen", "actors": "Schauspieler", - "artists": "Artists", - "albums": "Albums", - "songs": "Songs", + "artists": "Künstler", + "albums": "Alben", + "songs": "Titel", "playlists": "Playlists", "request_movies": "Film anfragen", "request_series": "Serie anfragen", "recently_added": "Kürzlich hinzugefügt", "recent_requests": "Kürzlich angefragt", - "plex_watchlist": "Plex Watchlist", - "trending": "In den Trends", + "plex_watchlist": "Plex Merkliste", + "trending": "Beliebt", "popular_movies": "Beliebte Filme", "movie_genres": "Film-Genres", "upcoming_movies": "Kommende Filme", "studios": "Studios", - "popular_tv": "Beliebte TV-Serien", - "tv_genres": "TV-Serien-Genres", - "upcoming_tv": "Kommende TV-Serien", - "networks": "Netzwerke", + "popular_tv": "Beliebte Serien", + "tv_genres": "Serien-Genres", + "upcoming_tv": "Kommende Serien", + "networks": "Sender", "tmdb_movie_keyword": "TMDB Film-Schlüsselwort", "tmdb_movie_genre": "TMDB Film-Genre", - "tmdb_tv_keyword": "TMDB TV-Serien-Schlüsselwort", - "tmdb_tv_genre": "TMDB TV-Serien-Genre", + "tmdb_tv_keyword": "TMDB Serien-Schlüsselwort", + "tmdb_tv_genre": "TMDB Serien-Genre", "tmdb_search": "TMDB Suche", "tmdb_studio": "TMDB Studio", "tmdb_network": "TMDB Netzwerk", "tmdb_movie_streaming_services": "TMDB Film-Streaming-Dienste", - "tmdb_tv_streaming_services": "TMDB TV-Serien-Streaming-Dienste" + "tmdb_tv_streaming_services": "TMDB Serien-Streaming-Dienste" }, "library": { "no_results": "Keine Ergebnisse", @@ -572,7 +572,7 @@ "genres": "Genres", "years": "Jahre", "sort_by": "Sortieren nach", - "filter_by": "Filter By", + "filter_by": "Filtern nach", "sort_order": "Sortierreihenfolge", "tags": "Tags" } @@ -585,7 +585,7 @@ "boxsets": "Boxsets", "playlists": "Wiedergabelisten", "noDataTitle": "Noch keine Favoriten", - "noData": "Markiere Elemente als Favoriten, damit sie hier für einen schnellen Zugriff angezeigt werden." + "noData": "Elemente als Favoriten markieren, um sie hier anzuzeigen." }, "custom_links": { "no_links": "Keine Links" @@ -593,7 +593,7 @@ "player": { "error": "Fehler", "failed_to_get_stream_url": "Fehler beim Abrufen der Stream-URL", - "an_error_occured_while_playing_the_video": "Ein Fehler ist beim Abspielen des Videos aufgetreten. Überprüf die Logs in den Einstellungen.", + "an_error_occured_while_playing_the_video": "Ein Fehler ist beim Abspielen des Videos aufgetreten. Logs in den Einstellungen überprüfen.", "client_error": "Client-Fehler", "could_not_create_stream_for_chromecast": "Konnte keinen Stream für Chromecast erstellen", "message_from_server": "Nachricht vom Server: {{message}}", @@ -602,17 +602,17 @@ "audio_tracks": "Audiospuren:", "playback_state": "Wiedergabestatus:", "index": "Index:", - "continue_watching": "Weiterschauen", + "continue_watching": "Fortsetzen", "go_back": "Zurück", - "downloaded_file_title": "Diese Datei wurde heruntergeladen", - "downloaded_file_message": "Möchten Sie die heruntergeladene Datei abspielen?", + "downloaded_file_title": "Diese Datei wurde bereits heruntergeladen", + "downloaded_file_message": "Heruntergeladene Datei abspielen?", "downloaded_file_yes": "Ja", "downloaded_file_no": "Nein", "downloaded_file_cancel": "Abbrechen" }, "item_card": { "next_up": "Als Nächstes", - "no_items_to_display": "Keine Elemente zum Anzeigen", + "no_items_to_display": "Keine Elemente", "cast_and_crew": "Besetzung und Crew", "series": "Serien", "seasons": "Staffeln", @@ -630,7 +630,7 @@ "subtitles": "Untertitel", "show_more": "Mehr anzeigen", "show_less": "Weniger anzeigen", - "appeared_in": "Erschienen in", + "appeared_in": "Erschien in", "could_not_load_item": "Konnte Element nicht laden", "none": "Keine", "download": { @@ -639,13 +639,13 @@ "download_episode": "Episode herunterladen", "download_movie": "Film herunterladen", "download_x_item": "{{item_count}} Elemente herunterladen", - "download_unwatched_only": "Nur unbeobachtete", + "download_unwatched_only": "Nur Ungesehene", "download_button": "Herunterladen" } }, "live_tv": { - "next": "Nächster", - "previous": "Vorheriger", + "next": "Nächste", + "previous": "Vorherige", "coming_soon": "Demnächst", "on_now": "Jetzt", "shows": "Serien", @@ -658,10 +658,10 @@ "confirm": "Bestätigen", "cancel": "Abbrechen", "yes": "Ja", - "whats_wrong": "Hast du Probleme?", - "issue_type": "Fehlerart", - "select_an_issue": "Wähle einen Fehlerart aus", - "types": "Arten", + "whats_wrong": "Was stimmt nicht?", + "issue_type": "Art des Problems", + "select_an_issue": "Wähle die Art des Problems aus", + "types": "Problem-Arten", "describe_the_issue": "(optional) Beschreibe das Problem", "submit_button": "Absenden", "report_issue_button": "Fehler melden", @@ -671,7 +671,7 @@ "cast": "Besetzung", "details": "Details", "status": "Status", - "original_title": "Original Titel", + "original_title": "Originaltitel", "series_type": "Serien Typ", "release_dates": "Veröffentlichungsdaten", "first_air_date": "Erstausstrahlungsdatum", @@ -687,10 +687,10 @@ "request_as": "Anfragen als", "tags": "Tags", "quality_profile": "Qualitätsprofil", - "root_folder": "Root-Ordner", - "season_all": "Season (all)", + "root_folder": "Stammverzeichnis", + "season_all": "Staffeln (alle)", "season_number": "Staffel {{season_number}}", - "number_episodes": "{{episode_number}} Folgen", + "number_episodes": "{{episode_number}} Episoden", "born": "Geboren", "appearances": "Auftritte", "approve": "Genehmigen", @@ -698,9 +698,9 @@ "requested_by": "Angefragt von {{user}}", "unknown_user": "Unbekannter Nutzer", "toasts": { - "jellyseer_does_not_meet_requirements": "Jellyseerr Server erfüllt nicht die Anforderungsversion. Bitte aktualisiere deinen Jellyseerr Server auf mindestens 2.0.0", - "jellyseerr_test_failed": "Jellyseerr-Test fehlgeschlagen. Bitte versuche es erneut.", - "failed_to_test_jellyseerr_server_url": "Fehler beim Testen der Jellyseerr-Server-URL", + "jellyseer_does_not_meet_requirements": "Seerr-Server erfüllt nicht die minimalen Versionsanforderungen. Bitte den Seerr-Server auf mindestens 2.0.0 aktualisieren.", + "jellyseerr_test_failed": "Seerr-Test fehlgeschlagen. Bitte erneut versuchen.", + "failed_to_test_jellyseerr_server_url": "Fehler beim Test der Seerr-Server-URL", "issue_submitted": "Problem eingereicht!", "requested_item": "{{item}} angefragt!", "you_dont_have_permission_to_request": "Du hast keine Berechtigung Anfragen zu stellen", @@ -715,131 +715,131 @@ "home": "Startseite", "search": "Suche", "library": "Bibliothek", - "custom_links": "Benutzerdefinierte Links", + "custom_links": "Links", "favorites": "Favoriten" }, "music": { - "title": "Music", + "title": "Musik", "tabs": { - "suggestions": "Suggestions", - "albums": "Albums", - "artists": "Artists", + "suggestions": "Vorschläge", + "albums": "Alben", + "artists": "Künstler", "playlists": "Playlists", - "tracks": "tracks" + "tracks": "Titel" }, "filters": { - "all": "All" + "all": "Alle" }, - "recently_added": "Recently Added", - "recently_played": "Recently Played", - "frequently_played": "Frequently Played", - "explore": "Explore", - "top_tracks": "Top Tracks", - "play": "Play", + "recently_added": "Kürzlich hinzugefügt", + "recently_played": "Vor kurzem gehört", + "frequently_played": "Oft gehört", + "explore": "Entdecken", + "top_tracks": "Top-Titel", + "play": "Abspielen", "shuffle": "Shuffle", - "play_top_tracks": "Play Top Tracks", - "no_suggestions": "No suggestions available", - "no_albums": "No albums found", - "no_artists": "No artists found", - "no_playlists": "No playlists found", - "album_not_found": "Album not found", - "artist_not_found": "Artist not found", - "playlist_not_found": "Playlist not found", + "play_top_tracks": "Top-Tracks abspielen", + "no_suggestions": "Keine Vorschläge verfügbar", + "no_albums": "Keine Alben gefunden", + "no_artists": "Keine Künstler gefunden", + "no_playlists": "Keine Playlists gefunden", + "album_not_found": "Album nicht gefunden", + "artist_not_found": "Künstler nicht gefunden", + "playlist_not_found": "Playlist nicht gefunden", "track_options": { - "play_next": "Play Next", - "add_to_queue": "Add to Queue", - "add_to_playlist": "Add to Playlist", - "download": "Download", - "downloaded": "Downloaded", - "downloading": "Downloading...", - "cached": "Cached", - "delete_download": "Delete Download", - "delete_cache": "Remove from Cache", - "go_to_artist": "Go to Artist", - "go_to_album": "Go to Album", - "add_to_favorites": "Add to Favorites", - "remove_from_favorites": "Remove from Favorites", - "remove_from_playlist": "Remove from Playlist" + "play_next": "Als Nächstes wiedergeben", + "add_to_queue": "Zur Warteschlange hinzufügen", + "add_to_playlist": "Zur Playlist hinzufügen", + "download": "Herunterladen", + "downloaded": "Heruntergeladen", + "downloading": "Wird heruntergeladen...", + "cached": "Gecached", + "delete_download": "Download löschen", + "delete_cache": "Aus dem Cache löschen", + "go_to_artist": "Zum Künstler gehen", + "go_to_album": "Zum Album gehen", + "add_to_favorites": "Zu Favoriten hinzufügen", + "remove_from_favorites": "Aus Favoriten entfernen", + "remove_from_playlist": "Aus Playlist entfernen" }, "playlists": { - "create_playlist": "Create Playlist", + "create_playlist": "Playlist erstellen", "playlist_name": "Playlist Name", - "enter_name": "Enter playlist name", - "create": "Create", - "search_playlists": "Search playlists...", - "added_to": "Added to {{name}}", - "added": "Added to playlist", - "removed_from": "Removed from {{name}}", - "removed": "Removed from playlist", - "created": "Playlist created", - "create_new": "Create New Playlist", - "failed_to_add": "Failed to add to playlist", - "failed_to_remove": "Failed to remove from playlist", - "failed_to_create": "Failed to create playlist", - "delete_playlist": "Delete Playlist", - "delete_confirm": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.", - "deleted": "Playlist deleted", - "failed_to_delete": "Failed to delete playlist" + "enter_name": "Playlist Name eingeben", + "create": "Erstellen", + "search_playlists": "Playlisten durchsuchen...", + "added_to": "Zu {{name}} hinzugefügt", + "added": "Zur Playlist hinzugefügt", + "removed_from": "Aus {{name}} entfernt", + "removed": "Aus Playlist entfernt", + "created": "Playlist erstellt", + "create_new": "Neue Playlist erstellen", + "failed_to_add": "Fehler beim Hinzufügen zur Playlist", + "failed_to_remove": "Fehler beim Entfernen aus der Playlist", + "failed_to_create": "Fehler beim Erstellen der Playlist", + "delete_playlist": "Playlist löschen", + "delete_confirm": "Bist Du sicher, dass Du \"{{name}}\" löschen möchtest? Das kann nicht rückgängig gemacht werden.", + "deleted": "Playlist gelöscht", + "failed_to_delete": "Fehler beim Löschen der Playlist" }, "sort": { - "title": "Sort By", - "alphabetical": "Alphabetical", - "date_created": "Date Created" + "title": "Sortieren nach", + "alphabetical": "Alphabetisch", + "date_created": "Erstellungsdatum" } }, "watchlists": { - "title": "Watchlists", - "my_watchlists": "My Watchlists", - "public_watchlists": "Public Watchlists", - "create_title": "Create Watchlist", - "edit_title": "Edit Watchlist", - "create_button": "Create Watchlist", - "save_button": "Save Changes", - "delete_button": "Delete", - "remove_button": "Remove", - "cancel_button": "Cancel", + "title": "Merklisten", + "my_watchlists": "Meine Merklisten", + "public_watchlists": "Öffentliche Merklisten", + "create_title": "Merkliste erstellen", + "edit_title": "Merkliste bearbeiten", + "create_button": "Merkliste erstellen", + "save_button": "Änderungen speichern", + "delete_button": "Löschen", + "remove_button": "Entfernen", + "cancel_button": "Abbrechen", "name_label": "Name", - "name_placeholder": "Enter watchlist name", - "description_label": "Description", - "description_placeholder": "Enter description (optional)", - "is_public_label": "Public Watchlist", - "is_public_description": "Allow others to view this watchlist", - "allowed_type_label": "Content Type", - "sort_order_label": "Default Sort Order", - "empty_title": "No Watchlists", - "empty_description": "Create your first watchlist to start organizing your media", - "empty_watchlist": "This watchlist is empty", - "empty_watchlist_hint": "Add items from your library to this watchlist", - "not_configured_title": "Streamystats Not Configured", - "not_configured_description": "Configure Streamystats in settings to use watchlists", - "go_to_settings": "Go to Settings", - "add_to_watchlist": "Add to Watchlist", - "remove_from_watchlist": "Remove from Watchlist", - "select_watchlist": "Select Watchlist", - "create_new": "Create New Watchlist", - "item": "item", - "items": "items", - "public": "Public", - "private": "Private", - "you": "You", - "by_owner": "By another user", - "not_found": "Watchlist not found", - "delete_confirm_title": "Delete Watchlist", - "delete_confirm_message": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.", - "remove_item_title": "Remove from Watchlist", - "remove_item_message": "Remove \"{{name}}\" from this watchlist?", - "loading": "Loading watchlists...", - "no_compatible_watchlists": "No compatible watchlists", - "create_one_first": "Create a watchlist that accepts this content type" + "name_placeholder": "Merklistenname eingeben", + "description_label": "Beschreibung", + "description_placeholder": "Beschreibung eingeben (optional)", + "is_public_label": "Öffentliche Merkliste", + "is_public_description": "Anderen erlauben diese Merkliste anzusehen", + "allowed_type_label": "Inhaltstyp", + "sort_order_label": "Standard-Sortierreihenfolge", + "empty_title": "Keine Merklisten", + "empty_description": "Erstelle deine erste Merkliste um deine Medien zu organisieren", + "empty_watchlist": "Diese Merkliste ist leer", + "empty_watchlist_hint": "Füge Elemente aus deiner Bibliothek zu dieser Merkliste hinzu", + "not_configured_title": "Streamystats nicht konfiguriert", + "not_configured_description": "Streamystats in den Einstellungen konfigurieren, um Merklisten zu verwenden", + "go_to_settings": "Gehe zu Einstellungen", + "add_to_watchlist": "Zur Merkliste hinzufügen", + "remove_from_watchlist": "Von Merkliste entfernen", + "select_watchlist": "Merkliste auswählen", + "create_new": "Neue Merkliste erstellen", + "item": "Element", + "items": "Elemente", + "public": "Öffentlich", + "private": "Privat", + "you": "Du", + "by_owner": "Von einem anderen Benutzer", + "not_found": "Merkliste nicht gefunden", + "delete_confirm_title": "Merkliste löschen", + "delete_confirm_message": "Bist Du sicher, dass Du \"{{name}}\" löschen möchtest? Das kann nicht rückgängig gemacht werden.", + "remove_item_title": "Von Merkliste entfernen", + "remove_item_message": "\"{{name}}\" von dieser Merkliste entfernen?", + "loading": "Lade Merklisten...", + "no_compatible_watchlists": "Keine kompatiblen Merklisten", + "create_one_first": "Erstelle eine Merkliste, welche diesen Inhaltstyp akzeptiert" }, "playback_speed": { - "title": "Playback Speed", - "apply_to": "Apply To", - "speed": "Speed", + "title": "Wiedergabegeschwindigkeit", + "apply_to": "Anwenden auf", + "speed": "Geschwindigkeit", "scope": { - "media": "This media only", - "show": "This show", - "all": "All media (default)" + "media": "Nur hier", + "show": "Nur diese Serie", + "all": "Alle (Standard)" } } } diff --git a/translations/es.json b/translations/es.json index 9ab662eb..c98493d9 100644 --- a/translations/es.json +++ b/translations/es.json @@ -39,39 +39,39 @@ "please_login_again": "Su sesión guardada ha caducado. Por favor, inicie sesión de nuevo.", "remove_saved_login": "Eliminar inicio de sesión guardado", "remove_saved_login_description": "Esto eliminará tus credenciales guardadas para este servidor. Tendrás que volver a introducir tu nombre de usuario y contraseña la próxima vez.", - "accounts_count": "{{count}} accounts", - "select_account": "Select Account", - "add_account": "Add Account", - "remove_account_description": "This will remove the saved credentials for {{username}}." + "accounts_count": "{{count}} cuentas", + "select_account": "Seleccione una cuenta", + "add_account": "Añadir cuenta", + "remove_account_description": "Esto eliminará las credenciales guardadas para {{username}}." }, "save_account": { - "title": "Save Account", - "save_for_later": "Save this account", - "security_option": "Security Option", - "no_protection": "No protection", - "no_protection_desc": "Quick login without authentication", - "pin_code": "PIN code", - "pin_code_desc": "4-digit PIN required when switching", - "password": "Re-enter password", - "password_desc": "Password required when switching", - "save_button": "Save", - "cancel_button": "Cancel" + "title": "Guardar Cuenta", + "save_for_later": "Guardar esta cuenta", + "security_option": "Opciones de seguridad", + "no_protection": "Sin Protección", + "no_protection_desc": "Inicio de sesión rápido sin autenticación", + "pin_code": "Código PIN", + "pin_code_desc": "PIN de 4 dígitos requerido al cambiar", + "password": "Vuelva a introducir la contraseña", + "password_desc": "Contraseña requerida al cambiar", + "save_button": "Guardar", + "cancel_button": "Cancelar" }, "pin": { - "enter_pin": "Enter PIN", - "enter_pin_for": "Enter PIN for {{username}}", - "enter_4_digits": "Enter 4 digits", - "invalid_pin": "Invalid PIN", - "setup_pin": "Set Up PIN", - "confirm_pin": "Confirm PIN", - "pins_dont_match": "PINs don't match", - "forgot_pin": "Forgot PIN?", - "forgot_pin_desc": "Your saved credentials will be removed" + "enter_pin": "Introduce el PIN", + "enter_pin_for": "Introduzca el PIN para {{username}}", + "enter_4_digits": "Introduce 4 dígitos", + "invalid_pin": "PIN inválido", + "setup_pin": "Configurar PIN", + "confirm_pin": "Confirmar PIN", + "pins_dont_match": "Los códigos PIN no coinciden", + "forgot_pin": "¿Olvidó el PIN?", + "forgot_pin_desc": "Sus credenciales guardadas serán eliminadas" }, "password": { - "enter_password": "Enter Password", - "enter_password_for": "Enter password for {{username}}", - "invalid_password": "Invalid password" + "enter_password": "Introduzca la contraseña", + "enter_password_for": "Introduzca la contraseña para {{username}}", + "invalid_password": "Contraseña inválida" }, "home": { "checking_server_connection": "Comprobando conexión con el servidor...", @@ -124,32 +124,32 @@ "hide_remote_session_button": "Ocultar botón de sesión remota" }, "network": { - "title": "Network", - "local_network": "Local Network", - "auto_switch_enabled": "Auto-switch when at home", - "auto_switch_description": "Automatically switch to local URL when connected to home WiFi", - "local_url": "Local URL", - "local_url_hint": "Enter your local server address (e.g., http://192.168.1.100:8096)", + "title": "Cadena", + "local_network": "Red local", + "auto_switch_enabled": "Cambiar automáticamente en casa", + "auto_switch_description": "Cambiar automáticamente a la URL local cuando se conecta a la WiFi de casa", + "local_url": "URL local", + "local_url_hint": "Introduzca la dirección de su servidor local (por ejemplo, http://192.168.1.100:8096)", "local_url_placeholder": "http://192.168.1.100:8096", - "home_wifi_networks": "Home WiFi Networks", - "add_current_network": "Add \"{{ssid}}\"", - "not_connected_to_wifi": "Not connected to WiFi", - "no_networks_configured": "No networks configured", - "add_network_hint": "Add your home WiFi network to enable auto-switching", - "current_wifi": "Current WiFi", - "using_url": "Using", - "local": "Local URL", - "remote": "Remote URL", - "not_connected": "Not connected", - "current_server": "Current Server", - "remote_url": "Remote URL", - "active_url": "Active URL", - "not_configured": "Not configured", - "network_added": "Network added", - "network_already_added": "Network already added", - "no_wifi_connected": "Not connected to WiFi", - "permission_denied": "Location permission denied", - "permission_denied_explanation": "Location permission is required to detect WiFi network for auto-switching. Please enable it in Settings." + "home_wifi_networks": "Redes WiFi domésticas", + "add_current_network": "Añadir \"{{ssid}}\"", + "not_connected_to_wifi": "No está conectado a WiFi", + "no_networks_configured": "No hay redes configuradas", + "add_network_hint": "Añade tu red WiFi doméstica para activar el cambio automático", + "current_wifi": "WiFi actual", + "using_url": "Utilizando", + "local": "URL local", + "remote": "URL Remota", + "not_connected": "Sin conexión", + "current_server": "Servidor actual", + "remote_url": "URL Remota", + "active_url": "URL Activa", + "not_configured": "Sin configurar", + "network_added": "Red añadida", + "network_already_added": "Red ya añadida", + "no_wifi_connected": "Sin conexión a WiFi", + "permission_denied": "Permiso de ubicación denegado", + "permission_denied_explanation": "Se necesita el permiso de ubicación para detectar la red WiFi para cambiar automáticamente. Por favor, actívala en Configuración." }, "user_info": { "user_info_title": "Información de usuario", @@ -195,12 +195,12 @@ "none": "Ninguno", "language": "Idioma", "transcode_mode": { - "title": "Audio Transcoding", - "description": "Controls how surround audio (7.1, TrueHD, DTS-HD) is handled", + "title": "Transcodificación de audio", + "description": "Controla cómo el audio envolvente (7.1, TrueHD, DTS-HD) es manejado", "auto": "Auto", - "stereo": "Force Stereo", - "5_1": "Allow 5.1", - "passthrough": "Passthrough" + "stereo": "Forzar salida estéreo", + "5_1": "Permitir 5.1", + "passthrough": "Directo" } }, "subtitles": { @@ -259,16 +259,16 @@ "hardware_decode_description": "Utilizar la aceleración de hardware para la decodificación de vídeo. Deshabilite si experimenta problemas de reproducción." }, "vlc_subtitles": { - "title": "VLC Subtitle Settings", - "hint": "Customize subtitle appearance for VLC player. Changes take effect on next playback.", - "text_color": "Text Color", - "background_color": "Background Color", - "background_opacity": "Background Opacity", - "outline_color": "Outline Color", - "outline_opacity": "Outline Opacity", - "outline_thickness": "Outline Thickness", - "bold": "Bold Text", - "margin": "Bottom Margin" + "title": "Configuración de subtítulos VLC", + "hint": "Personalizar la apariencia de los subtítulos para el reproductor VLC. Los cambios tendrán efecto en la próxima reproducción.", + "text_color": "Color del texto", + "background_color": "Color del fondo", + "background_opacity": "Opacidad del fondo", + "outline_color": "Color del contorno", + "outline_opacity": "Opacidad del contorno", + "outline_thickness": "Grosor del contorno", + "bold": "Texto en negrita", + "margin": "Margen inferior" }, "video_player": { "title": "Reproductor de vídeo", @@ -300,13 +300,13 @@ "VLC_4": "VLC 4 (Experimental + PiP)" }, "show_custom_menu_links": "Mostrar enlaces de menú personalizados", - "show_large_home_carousel": "Show Large Home Carousel (beta)", + "show_large_home_carousel": "Mostrar carrusel del menú principal grande (beta)", "hide_libraries": "Ocultar bibliotecas", "select_liraries_you_want_to_hide": "Selecciona las bibliotecas que quieres ocultar de la pestaña Bibliotecas y de Inicio.", "disable_haptic_feedback": "Desactivar feedback háptico", "default_quality": "Calidad por defecto", "default_playback_speed": "Velocidad de reproducción predeterminada", - "auto_play_next_episode": "Auto-play Next Episode", + "auto_play_next_episode": "Reproducir automáticamente el siguiente episodio", "max_auto_play_episode_count": "Máximo número de episodios de Auto Play", "disabled": "Deshabilitado" }, @@ -317,10 +317,10 @@ "title": "Música", "playback_title": "Reproducir", "playback_description": "Configurar cómo se reproduce la música.", - "prefer_downloaded": "Prefer Downloaded Songs", + "prefer_downloaded": "Preferir las canciones descargadas", "caching_title": "Almacenando en caché", - "caching_description": "Automatically cache upcoming tracks for smoother playback.", - "lookahead_enabled": "Enable Look-Ahead Caching", + "caching_description": "Cachear automáticamente las próximas canciones para una reproducción más suave.", + "lookahead_enabled": "Activar el look-Ahead Cache", "lookahead_count": "", "max_cache_size": "Tamaño máximo del caché" }, @@ -399,7 +399,7 @@ "size_used": "{{used}} de {{total}} usado", "delete_all_downloaded_files": "Eliminar todos los archivos descargados", "music_cache_title": "Caché de música", - "music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support", + "music_cache_description": "Cachear automáticamente las canciones mientras escuchas una reproducción más suave y soporte sin conexión", "enable_music_cache": "Activar Caché de Música", "clear_music_cache": "Borrar Caché de Música", "music_cache_size": "Caché {{Tamaño}}", @@ -504,10 +504,10 @@ "delete": "Borrar", "ok": "Aceptar", "remove": "Eliminar", - "next": "Next", - "back": "Back", - "continue": "Continue", - "verifying": "Verifying..." + "next": "Siguiente", + "back": "Atrás", + "continue": "Continuar", + "verifying": "Verificando..." }, "search": { "search": "Buscar...", @@ -753,8 +753,8 @@ "downloaded": "Descargado", "downloading": "Descargando...", "cached": "En caché", - "delete_download": "Delete Download", - "delete_cache": "Remove from Cache", + "delete_download": "Eliminar descarga", + "delete_cache": "Borrar del caché", "go_to_artist": "Ir al artista", "go_to_album": "Ir al álbum", "add_to_favorites": "Añadir a Favoritos", diff --git a/translations/fr.json b/translations/fr.json index 21fef280..b2663cd6 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -305,8 +305,8 @@ "select_liraries_you_want_to_hide": "Sélectionnez les bibliothèques que vous souhaitez masquer dans l'onglet Bibliothèque et les sections de la page d'accueil.", "disable_haptic_feedback": "Désactiver le retour haptique", "default_quality": "Qualité par défaut", - "default_playback_speed": "Default Playback Speed", - "auto_play_next_episode": "Auto-play Next Episode", + "default_playback_speed": "Vitesse de lecture par défaut", + "auto_play_next_episode": "Lecture automatique de l'épisode suivant", "max_auto_play_episode_count": "Nombre d'épisodes en lecture automatique max", "disabled": "Désactivé" }, @@ -314,15 +314,15 @@ "downloads_title": "Téléchargements" }, "music": { - "title": "Music", - "playback_title": "Playback", - "playback_description": "Configure how music is played.", - "prefer_downloaded": "Prefer Downloaded Songs", - "caching_title": "Caching", - "caching_description": "Automatically cache upcoming tracks for smoother playback.", - "lookahead_enabled": "Enable Look-Ahead Caching", - "lookahead_count": "Tracks to Pre-cache", - "max_cache_size": "Max Cache Size" + "title": "Musique", + "playback_title": "Lecture", + "playback_description": "Configurer le mode de lecture de la musique.", + "prefer_downloaded": "Supprimer toutes les musiques téléchargées", + "caching_title": "Mise en cache", + "caching_description": "Mettre automatiquement en cache les pistes à venir pour une lecture plus fluide.", + "lookahead_enabled": "Activer la mise en cache guidée", + "lookahead_count": "Pistes à pré-mettre en cache", + "max_cache_size": "Taille max de cache" }, "plugins": { "plugins_title": "Plugins", @@ -357,19 +357,19 @@ "save_button": "Enregistrer", "toasts": { "saved": "Enregistré", - "refreshed": "Settings refreshed from server" + "refreshed": "Paramètres actualisés depuis le serveur" }, - "refresh_from_server": "Refresh Settings from Server" + "refresh_from_server": "Rafraîchir les paramètres depuis le serveur" }, "streamystats": { - "enable_streamystats": "Enable Streamystats", - "disable_streamystats": "Disable Streamystats", - "enable_search": "Use for Search", + "enable_streamystats": "Activer Streamystats", + "disable_streamystats": "Désactiver Streamystats", + "enable_search": "Utiliser pour la recherche", "url": "URL", "server_url_placeholder": "http(s)://streamystats.example.com", - "streamystats_search_hint": "Enter the URL for your Streamystats server. The URL should include http or https and optionally the port.", - "read_more_about_streamystats": "Read More About Streamystats.", - "save_button": "Save", + "streamystats_search_hint": "Entrez l'URL de votre serveur Streamystats. L'URL doit inclure http ou https et éventuellement le port.", + "read_more_about_streamystats": "En savoir plus sur Streamystats.", + "save_button": "Enregistrer", "save": "Enregistrer", "features_title": "Fonctionnalités", "home_sections_title": "Sections de la page d´accueil", @@ -572,7 +572,7 @@ "genres": "Genres", "years": "Années", "sort_by": "Trier par", - "filter_by": "Filter By", + "filter_by": "Filtrer par", "sort_order": "Ordre de tri", "tags": "Tags" } @@ -719,127 +719,127 @@ "favorites": "Favoris" }, "music": { - "title": "Music", + "title": "Musique", "tabs": { "suggestions": "Suggestions", "albums": "Albums", - "artists": "Artists", + "artists": "Artistes", "playlists": "Playlists", - "tracks": "tracks" + "tracks": "morceaux" }, "filters": { - "all": "All" + "all": "Toutes" }, - "recently_added": "Recently Added", - "recently_played": "Recently Played", - "frequently_played": "Frequently Played", - "explore": "Explore", - "top_tracks": "Top Tracks", - "play": "Play", - "shuffle": "Shuffle", - "play_top_tracks": "Play Top Tracks", - "no_suggestions": "No suggestions available", - "no_albums": "No albums found", - "no_artists": "No artists found", - "no_playlists": "No playlists found", - "album_not_found": "Album not found", - "artist_not_found": "Artist not found", - "playlist_not_found": "Playlist not found", + "recently_added": "Ajoutés récemment", + "recently_played": "Récemment joué", + "frequently_played": "Fréquemment joué", + "explore": "Explorez", + "top_tracks": "Top chansons", + "play": "Lecture", + "shuffle": "Aléatoire", + "play_top_tracks": "Jouer les pistes les plus populaires", + "no_suggestions": "Pas de suggestion disponible", + "no_albums": "Pas d'albums trouvés", + "no_artists": "Pas d'artistes trouvé", + "no_playlists": "Pas de playlists trouvées", + "album_not_found": "Album introuvable", + "artist_not_found": "Artiste introuvable", + "playlist_not_found": "Playlist introuvable", "track_options": { - "play_next": "Play Next", - "add_to_queue": "Add to Queue", - "add_to_playlist": "Add to Playlist", - "download": "Download", - "downloaded": "Downloaded", - "downloading": "Downloading...", - "cached": "Cached", - "delete_download": "Delete Download", - "delete_cache": "Remove from Cache", - "go_to_artist": "Go to Artist", - "go_to_album": "Go to Album", - "add_to_favorites": "Add to Favorites", - "remove_from_favorites": "Remove from Favorites", - "remove_from_playlist": "Remove from Playlist" + "play_next": "Lecture suivante", + "add_to_queue": "Ajouter à la file d'attente", + "add_to_playlist": "Ajouter à la playlist", + "download": "Télécharger", + "downloaded": "Téléchargé", + "downloading": "Téléchargement en cours...", + "cached": "En cache", + "delete_download": "Supprimer un téléchargement", + "delete_cache": "Supprimer du cache", + "go_to_artist": "Voir l'artiste", + "go_to_album": "Aller à l’album", + "add_to_favorites": "Ajouter aux favoris", + "remove_from_favorites": "Retirer des favoris", + "remove_from_playlist": "Retirer de la playlist" }, "playlists": { - "create_playlist": "Create Playlist", - "playlist_name": "Playlist Name", - "enter_name": "Enter playlist name", - "create": "Create", - "search_playlists": "Search playlists...", - "added_to": "Added to {{name}}", - "added": "Added to playlist", - "removed_from": "Removed from {{name}}", - "removed": "Removed from playlist", - "created": "Playlist created", - "create_new": "Create New Playlist", - "failed_to_add": "Failed to add to playlist", - "failed_to_remove": "Failed to remove from playlist", - "failed_to_create": "Failed to create playlist", - "delete_playlist": "Delete Playlist", - "delete_confirm": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.", - "deleted": "Playlist deleted", - "failed_to_delete": "Failed to delete playlist" + "create_playlist": "Créer une Playlist", + "playlist_name": "Nom de la Playlist", + "enter_name": "Entrer le nom de la playlist", + "create": "Créer", + "search_playlists": "Rechercher des playlists...", + "added_to": "Ajouté à {{name}}", + "added": "Ajouté à la playlist", + "removed_from": "Retiré de {{name}}", + "removed": "Retiré de la playlist", + "created": "Playlist créée", + "create_new": "Créer une nouvelle playlist", + "failed_to_add": "Échec de l'ajout à la playlist", + "failed_to_remove": "Échec de la suppression de la playlist", + "failed_to_create": "Échec de la suppression de la playlist", + "delete_playlist": "Supprimer la playlist", + "delete_confirm": "Êtes-vous sûr de vouloir supprimer « {{ name }} » ? Cette action est irréversible.", + "deleted": "Playlist supprimée", + "failed_to_delete": "Échec de la suppression de la playlist" }, "sort": { - "title": "Sort By", - "alphabetical": "Alphabetical", - "date_created": "Date Created" + "title": "Trier par", + "alphabetical": "Ordre alphabétique", + "date_created": "Date de création" } }, "watchlists": { "title": "Watchlists", "my_watchlists": "My Watchlists", - "public_watchlists": "Public Watchlists", - "create_title": "Create Watchlist", - "edit_title": "Edit Watchlist", - "create_button": "Create Watchlist", - "save_button": "Save Changes", - "delete_button": "Delete", - "remove_button": "Remove", - "cancel_button": "Cancel", - "name_label": "Name", - "name_placeholder": "Enter watchlist name", + "public_watchlists": "Watchlist publique", + "create_title": "Créer une Watchlist", + "edit_title": "Modifier la Watchlist", + "create_button": "Créer une Watchlist", + "save_button": "Enregistrer les modifications", + "delete_button": "Supprimer", + "remove_button": "Retirer", + "cancel_button": "Annuler", + "name_label": "Nom", + "name_placeholder": "Entrer le nom de la playlist", "description_label": "Description", - "description_placeholder": "Enter description (optional)", + "description_placeholder": "Entrez la description (facultatif)", "is_public_label": "Public Watchlist", - "is_public_description": "Allow others to view this watchlist", - "allowed_type_label": "Content Type", - "sort_order_label": "Default Sort Order", - "empty_title": "No Watchlists", - "empty_description": "Create your first watchlist to start organizing your media", - "empty_watchlist": "This watchlist is empty", - "empty_watchlist_hint": "Add items from your library to this watchlist", - "not_configured_title": "Streamystats Not Configured", - "not_configured_description": "Configure Streamystats in settings to use watchlists", - "go_to_settings": "Go to Settings", - "add_to_watchlist": "Add to Watchlist", - "remove_from_watchlist": "Remove from Watchlist", - "select_watchlist": "Select Watchlist", - "create_new": "Create New Watchlist", - "item": "item", - "items": "items", - "public": "Public", - "private": "Private", - "you": "You", - "by_owner": "By another user", - "not_found": "Watchlist not found", - "delete_confirm_title": "Delete Watchlist", - "delete_confirm_message": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.", - "remove_item_title": "Remove from Watchlist", - "remove_item_message": "Remove \"{{name}}\" from this watchlist?", - "loading": "Loading watchlists...", - "no_compatible_watchlists": "No compatible watchlists", - "create_one_first": "Create a watchlist that accepts this content type" + "is_public_description": "Autoriser d'autres personnes à voir cette liste de suivi", + "allowed_type_label": "Type de contenu", + "sort_order_label": "Ordre de tri par défaut", + "empty_title": "Pas de Watchlists", + "empty_description": "Créez votre première liste de suivi pour commencer à organiser vos médias", + "empty_watchlist": "Cette liste de suivi est vide", + "empty_watchlist_hint": "Ajouter des éléments de votre bibliothèque à cette liste de suivi", + "not_configured_title": "Streamystats non configuré", + "not_configured_description": "Configurer Streamystats dans les paramètres pour utiliser les listes de suivi", + "go_to_settings": "Accédez aux Paramètres", + "add_to_watchlist": "Ajouter à la Watchlist", + "remove_from_watchlist": "Retirer de la Watchlist", + "select_watchlist": "Sélectionner la liste de suivi", + "create_new": "Créer une Watchlist", + "item": "médias", + "items": "élément", + "public": "Publique", + "private": "Privée", + "you": "Vous-même", + "by_owner": "Par un autre utilisateur", + "not_found": "Playlist introuvable", + "delete_confirm_title": "Supprimer la Watchlist", + "delete_confirm_message": "Tous les médias (par défaut)", + "remove_item_title": "Retirer de la Watchlist", + "remove_item_message": "Retirer «{{name}}» de cette liste de suivi?", + "loading": "Chargement des listes de suivi...", + "no_compatible_watchlists": "Aucune liste de suivi compatible", + "create_one_first": "Créer une liste de suivi qui accepte ce type de contenu" }, "playback_speed": { - "title": "Playback Speed", - "apply_to": "Apply To", - "speed": "Speed", + "title": "Vitesse de lecture", + "apply_to": "Appliquer à", + "speed": "Vitesse", "scope": { - "media": "This media only", - "show": "This show", - "all": "All media (default)" + "media": "Ce média uniquement", + "show": "Cette série", + "all": "Tous les médias (par défaut)" } } } diff --git a/translations/it.json b/translations/it.json index a6de11c1..604934b7 100644 --- a/translations/it.json +++ b/translations/it.json @@ -34,9 +34,9 @@ "search_for_local_servers": "Ricerca dei server locali", "searching": "Cercando...", "servers": "Server", - "saved": "Saved", + "saved": "Salvato", "session_expired": "Session Expired", - "please_login_again": "Your saved session has expired. Please log in again.", + "please_login_again": "La tua sessione è scaduta. Si prega di eseguire nuovamente l'accesso.", "remove_saved_login": "Remove Saved Login", "remove_saved_login_description": "This will remove your saved credentials for this server. You'll need to enter your username and password again next time.", "accounts_count": "{{count}} accounts", @@ -125,7 +125,7 @@ }, "network": { "title": "Network", - "local_network": "Local Network", + "local_network": "", "auto_switch_enabled": "Auto-switch when at home", "auto_switch_description": "Automatically switch to local URL when connected to home WiFi", "local_url": "Local URL", @@ -137,7 +137,7 @@ "no_networks_configured": "No networks configured", "add_network_hint": "Add your home WiFi network to enable auto-switching", "current_wifi": "Current WiFi", - "using_url": "Using", + "using_url": "Sta utilizzando", "local": "Local URL", "remote": "Remote URL", "not_connected": "Not connected", diff --git a/translations/nl.json b/translations/nl.json index 326f9a1e..375aeab1 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -30,7 +30,7 @@ "connect_button": "Verbinden", "previous_servers": "vorige servers", "clear_button": "Wissen", - "swipe_to_remove": "Swipe to remove", + "swipe_to_remove": "Swipe om te verwijderen.", "search_for_local_servers": "Zoek naar lokale servers", "searching": "Zoeken...", "servers": "Servers", @@ -40,38 +40,38 @@ "remove_saved_login": "Opgeslagen login verwijderen", "remove_saved_login_description": "Hiermee worden uw opgeslagen gegevens voor deze server verwijderd. U moet uw gebruikersnaam en wachtwoord de volgende keer opnieuw invoeren.", "accounts_count": "{{count}} accounts", - "select_account": "Select Account", - "add_account": "Add Account", - "remove_account_description": "This will remove the saved credentials for {{username}}." + "select_account": "Account selecteren", + "add_account": "Account toevoegen", + "remove_account_description": "Hiermee worden de opgeslagen inloggegevens voor {{username}} verwijderd." }, "save_account": { - "title": "Save Account", - "save_for_later": "Save this account", - "security_option": "Security Option", - "no_protection": "No protection", - "no_protection_desc": "Quick login without authentication", - "pin_code": "PIN code", - "pin_code_desc": "4-digit PIN required when switching", - "password": "Re-enter password", - "password_desc": "Password required when switching", - "save_button": "Save", - "cancel_button": "Cancel" + "title": "Account opslaan", + "save_for_later": "Dit account opslaan", + "security_option": "Beveiligingsopties", + "no_protection": "Geen beveiliging", + "no_protection_desc": "Snelle login zonder authenticatie", + "pin_code": "Pincode", + "pin_code_desc": "4-cijferige pincode vereist bij wisselen", + "password": "Wachtwoord opnieuw invoeren", + "password_desc": "Wachtwoord vereist bij wisselen", + "save_button": "Opslaan", + "cancel_button": "Annuleren" }, "pin": { - "enter_pin": "Enter PIN", - "enter_pin_for": "Enter PIN for {{username}}", - "enter_4_digits": "Enter 4 digits", - "invalid_pin": "Invalid PIN", - "setup_pin": "Set Up PIN", - "confirm_pin": "Confirm PIN", - "pins_dont_match": "PINs don't match", - "forgot_pin": "Forgot PIN?", - "forgot_pin_desc": "Your saved credentials will be removed" + "enter_pin": "Pincode invoeren", + "enter_pin_for": "Pincode voor {{username}} invoeren", + "enter_4_digits": "Voer 6 cijfers in", + "invalid_pin": "Ongeldige pincode", + "setup_pin": "Pincode instellen", + "confirm_pin": "Pincode bevestigen", + "pins_dont_match": "Pincodes komen niet overeen", + "forgot_pin": "Pincode vergeten?", + "forgot_pin_desc": "Je opgeslagen inloggegevens worden verwijderd" }, "password": { - "enter_password": "Enter Password", - "enter_password_for": "Enter password for {{username}}", - "invalid_password": "Invalid password" + "enter_password": "Voer wachtwoord in", + "enter_password_for": "Voer wachtwoord voor {{username}} in", + "invalid_password": "Ongeldig wachtwoord" }, "home": { "checking_server_connection": "Serververbinding controleren...", @@ -84,7 +84,7 @@ "server_unreachable": "Server onbereikbaar", "server_unreachable_message": "Kon de server niet bereiken.\nControleer uw netwerkverbinding.", "oops": "Oeps!", - "error_message": "Er ging iets fout\nGelieve af en aan te melden.", + "error_message": "Er ging iets fout\nProbeer opnieuw in te loggen.", "continue_watching": "Verder Kijken", "next_up": "Volgende", "continue_and_next_up": "Doorgaan & Volgende", @@ -124,32 +124,32 @@ "hide_remote_session_button": "Verberg Knop voor Externe Sessie" }, "network": { - "title": "Network", - "local_network": "Local Network", - "auto_switch_enabled": "Auto-switch when at home", - "auto_switch_description": "Automatically switch to local URL when connected to home WiFi", - "local_url": "Local URL", - "local_url_hint": "Enter your local server address (e.g., http://192.168.1.100:8096)", + "title": "Netwerk", + "local_network": "Lokaal netwerk", + "auto_switch_enabled": "Automatisch wisselen wanneer thuis", + "auto_switch_description": "Automatisch wisselen naar lokale URL wanneer verbonden met thuisnetwerk", + "local_url": "Lokale URL", + "local_url_hint": "Voer uw lokale serveradres in (bijv. http://192.168.1.100:8096)", "local_url_placeholder": "http://192.168.1.100:8096", - "home_wifi_networks": "Home WiFi Networks", - "add_current_network": "Add \"{{ssid}}\"", - "not_connected_to_wifi": "Not connected to WiFi", - "no_networks_configured": "No networks configured", - "add_network_hint": "Add your home WiFi network to enable auto-switching", - "current_wifi": "Current WiFi", - "using_url": "Using", - "local": "Local URL", - "remote": "Remote URL", - "not_connected": "Not connected", - "current_server": "Current Server", - "remote_url": "Remote URL", - "active_url": "Active URL", - "not_configured": "Not configured", - "network_added": "Network added", - "network_already_added": "Network already added", - "no_wifi_connected": "Not connected to WiFi", - "permission_denied": "Location permission denied", - "permission_denied_explanation": "Location permission is required to detect WiFi network for auto-switching. Please enable it in Settings." + "home_wifi_networks": "Wi-Fi netwerken", + "add_current_network": "Voeg \"{{ssid}} \" toe", + "not_connected_to_wifi": "Niet verbonden met Wi-Fi", + "no_networks_configured": "Geen netwerken geconfigureerd", + "add_network_hint": "Voeg je thuisnetwerk toe om automatisch wisselen in te schakelen", + "current_wifi": "Huidige Wi-Fi", + "using_url": "Gebruik makend van", + "local": "Lokale URL", + "remote": "Externe URL", + "not_connected": "Niet verbonden", + "current_server": "Huidige Server", + "remote_url": "Externe URL", + "active_url": "Actieve URL", + "not_configured": "Niet geconfigureerd", + "network_added": "Netwerk toegevoegd", + "network_already_added": "Netwerk reeds toegevoegd", + "no_wifi_connected": "Niet verbonden met Wi-Fi", + "permission_denied": "Locatie toestemming geweigerd", + "permission_denied_explanation": "Locatie permissie is vereist om Wifi-netwerk te kunnen detecteren voor automatisch wisselen. Schakel het in via Instellingen." }, "user_info": { "user_info_title": "Gebruiker Info", @@ -195,11 +195,11 @@ "none": "Geen", "language": "Taal", "transcode_mode": { - "title": "Audio Transcoding", - "description": "Controls how surround audio (7.1, TrueHD, DTS-HD) is handled", - "auto": "Auto", - "stereo": "Force Stereo", - "5_1": "Allow 5.1", + "title": "Audio-transcoding", + "description": "Bepaalt hoe surround audio (7.1, TrueHD, DTS-HD) wordt behandeld", + "auto": "Automatisch", + "stereo": "Stereo forceren", + "5_1": "5.1 toestaan", "passthrough": "Passthrough" } }, @@ -231,7 +231,7 @@ "Black": "Zwart", "Gray": "Grijs", "Silver": "Zilver", - "White": "wit", + "White": "Wit", "Maroon": "Kastanjebruin", "Red": "Rood", "Fuchsia": "Fuchsia", @@ -259,14 +259,14 @@ "hardware_decode_description": "Gebruik hardware acceleratie voor video-decodering. Uitschakelen als u problemen met afspelen ondervindt." }, "vlc_subtitles": { - "title": "VLC Subtitle Settings", - "hint": "Customize subtitle appearance for VLC player. Changes take effect on next playback.", - "text_color": "Text Color", - "background_color": "Background Color", - "background_opacity": "Background Opacity", - "outline_color": "Outline Color", - "outline_opacity": "Outline Opacity", - "outline_thickness": "Outline Thickness", + "title": "VLC ondertitel instellingen", + "hint": "Aanpassen van ondertiteling voor VLC-speler. Wijzigingen worden toegepast bij het afspelen.", + "text_color": "Tekstkleur", + "background_color": "Achtergrondkleur", + "background_opacity": "Doorzichtigheid achtergrond", + "outline_color": "Kleur omlijning", + "outline_opacity": "Omtrek opaciteit", + "outline_thickness": "Omtrek dikte", "bold": "Bold Text", "margin": "Bottom Margin" }, @@ -306,7 +306,7 @@ "disable_haptic_feedback": "Haptische feedback uitschakelen", "default_quality": "Standaard kwaliteit", "default_playback_speed": "Standaard Afspeelsnelheid", - "auto_play_next_episode": "Auto-play Next Episode", + "auto_play_next_episode": "Volgende aflevering automatisch afspelen", "max_auto_play_episode_count": "Max Automatisch Aflevering Aantal", "disabled": "Uitgeschakeld" }, @@ -378,12 +378,12 @@ "enable_promoted_watchlists": "Gepromote Kijklijst", "hide_watchlists_tab": "Hide Watchlists Tab", "home_sections_hint": "Show personalized recommendations and promoted watchlists from Streamystats on the home page.", - "recommended_movies": "Recommended Movies", - "recommended_series": "Recommended Series", + "recommended_movies": "Aanbevolen films", + "recommended_series": "Aanbevolen serie", "toasts": { - "saved": "Saved", + "saved": "Opgeslagen", "refreshed": "Settings refreshed from server", - "disabled": "Streamystats disabled" + "disabled": "Streamystats uitgeschakeld" }, "refresh_from_server": "Refresh Settings from Server" }, @@ -402,24 +402,24 @@ "music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support", "enable_music_cache": "Enable Music Cache", "clear_music_cache": "Clear Music Cache", - "music_cache_size": "{{size}} cached", - "music_cache_cleared": "Music cache cleared", - "delete_all_downloaded_songs": "Delete All Downloaded Songs", - "downloaded_songs_size": "{{size}} downloaded", + "music_cache_size": "{{size}} gecached", + "music_cache_cleared": "Muziek cache gewist", + "delete_all_downloaded_songs": "Verwijder alle gedownloade liedjes", + "downloaded_songs_size": "{{size}} gedownload", "downloaded_songs_deleted": "Downloaded songs deleted" }, "intro": { "title": "Intro", "show_intro": "Toon intro", - "reset_intro": "intro opnieuw instellen" + "reset_intro": "Reset Intro" }, "logs": { "logs_title": "Logboek", "export_logs": "Export logs", - "click_for_more_info": "Click for more info", + "click_for_more_info": "Klik voor meer info", "level": "Niveau", "no_logs_available": "Geen logs beschikbaar", - "delete_all_logs": "Verwijder alle logs" + "delete_all_logs": "Alle logs verwijderen" }, "languages": { "title": "Talen", @@ -500,14 +500,14 @@ "play": "Afspelen", "none": "Geen", "track": "Spoor", - "cancel": "Cancel", - "delete": "Delete", - "ok": "OK", - "remove": "Remove", - "next": "Next", - "back": "Back", - "continue": "Continue", - "verifying": "Verifying..." + "cancel": "Annuleren", + "delete": "Verwijderen", + "ok": "Oké", + "remove": "Verwijderen", + "next": "Volgende", + "back": "Terug", + "continue": "Doorgaan", + "verifying": "Verifiëren..." }, "search": { "search": "Zoek...", @@ -521,10 +521,10 @@ "episodes": "Afleveringen", "collections": "Collecties", "actors": "Acteurs", - "artists": "Artists", + "artists": "Artiesten", "albums": "Albums", - "songs": "Songs", - "playlists": "Playlists", + "songs": "Nummers", + "playlists": "Afspeellijsten", "request_movies": "Vraag films aan", "request_series": "Vraag series aan", "recently_added": "Recent Toegevoegd", @@ -572,7 +572,7 @@ "genres": "Genres", "years": "Jaren", "sort_by": "Sorteren op", - "filter_by": "Filter By", + "filter_by": "Filteren op", "sort_order": "Sorteer volgorde", "tags": "Labels" } @@ -719,127 +719,127 @@ "favorites": "Favorieten" }, "music": { - "title": "Music", + "title": "Muziek", "tabs": { - "suggestions": "Suggestions", + "suggestions": "Suggesties", "albums": "Albums", - "artists": "Artists", - "playlists": "Playlists", - "tracks": "tracks" + "artists": "Artiesten", + "playlists": "Afspeellijsten", + "tracks": "Nummers" }, "filters": { - "all": "All" + "all": "Alle" }, - "recently_added": "Recently Added", - "recently_played": "Recently Played", - "frequently_played": "Frequently Played", - "explore": "Explore", + "recently_added": "Recent toegevoegd", + "recently_played": "Onlangs afgespeeld", + "frequently_played": "Vaak afgespeeld", + "explore": "Ontdek", "top_tracks": "Top Tracks", - "play": "Play", + "play": "Afspelen", "shuffle": "Shuffle", "play_top_tracks": "Play Top Tracks", - "no_suggestions": "No suggestions available", - "no_albums": "No albums found", - "no_artists": "No artists found", - "no_playlists": "No playlists found", - "album_not_found": "Album not found", - "artist_not_found": "Artist not found", - "playlist_not_found": "Playlist not found", + "no_suggestions": "Geen suggesties beschikbaar", + "no_albums": "Geen albums gevonden", + "no_artists": "Geen artiesten gevonden", + "no_playlists": "Geen afspeellijsten gevonden", + "album_not_found": "Album niet gevonden", + "artist_not_found": "Artiest niet gevonden", + "playlist_not_found": "Afspeellijst niet gevonden", "track_options": { - "play_next": "Play Next", - "add_to_queue": "Add to Queue", - "add_to_playlist": "Add to Playlist", - "download": "Download", - "downloaded": "Downloaded", - "downloading": "Downloading...", - "cached": "Cached", - "delete_download": "Delete Download", - "delete_cache": "Remove from Cache", - "go_to_artist": "Go to Artist", - "go_to_album": "Go to Album", - "add_to_favorites": "Add to Favorites", - "remove_from_favorites": "Remove from Favorites", - "remove_from_playlist": "Remove from Playlist" + "play_next": "Speel volgende af", + "add_to_queue": "Toevoegen aan wachtrij", + "add_to_playlist": "Voeg toe aan afspeellijst", + "download": "Downloaden", + "downloaded": "Gedownload", + "downloading": "Downloaden...", + "cached": "Gecached", + "delete_download": "Download verwijderen", + "delete_cache": "Verwijderen uit cache", + "go_to_artist": "Ga naar artiest", + "go_to_album": "Ga naar album", + "add_to_favorites": "Toevoegen aan favorieten", + "remove_from_favorites": "Verwijderen uit favorieten", + "remove_from_playlist": "Verwijder uit afspeellijst" }, "playlists": { - "create_playlist": "Create Playlist", - "playlist_name": "Playlist Name", + "create_playlist": "Afspeellijst aanmaken", + "playlist_name": "Afspeellijst naam", "enter_name": "Enter playlist name", - "create": "Create", - "search_playlists": "Search playlists...", - "added_to": "Added to {{name}}", - "added": "Added to playlist", - "removed_from": "Removed from {{name}}", - "removed": "Removed from playlist", + "create": "Aanmaken", + "search_playlists": "Playlist zoeken...", + "added_to": "Toegevoegd aan {{name}}", + "added": "Toegevoegd aan playlist", + "removed_from": "Verwijderd uit {{name}}", + "removed": "Verwijderd uit playlist", "created": "Playlist created", "create_new": "Create New Playlist", "failed_to_add": "Failed to add to playlist", - "failed_to_remove": "Failed to remove from playlist", - "failed_to_create": "Failed to create playlist", - "delete_playlist": "Delete Playlist", - "delete_confirm": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.", - "deleted": "Playlist deleted", - "failed_to_delete": "Failed to delete playlist" + "failed_to_remove": "Verwijderen uit afspeellijst is mislukt", + "failed_to_create": "Het maken van de afspeellijst is mislukt", + "delete_playlist": "Afspeellijst verwijderen", + "delete_confirm": "Weet u zeker dat u \"{{name}}\"wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.", + "deleted": "Afspeellijst verwijderd.", + "failed_to_delete": "Verwijderen van afspeellijst mislukt" }, "sort": { - "title": "Sort By", - "alphabetical": "Alphabetical", - "date_created": "Date Created" + "title": "Sorteren op", + "alphabetical": "Alfabetisch", + "date_created": "Aanmaakdatum" } }, "watchlists": { - "title": "Watchlists", - "my_watchlists": "My Watchlists", + "title": "Watchlist", + "my_watchlists": "Mijn watchlists", "public_watchlists": "Public Watchlists", "create_title": "Create Watchlist", "edit_title": "Edit Watchlist", "create_button": "Create Watchlist", - "save_button": "Save Changes", - "delete_button": "Delete", - "remove_button": "Remove", - "cancel_button": "Cancel", - "name_label": "Name", - "name_placeholder": "Enter watchlist name", - "description_label": "Description", - "description_placeholder": "Enter description (optional)", - "is_public_label": "Public Watchlist", - "is_public_description": "Allow others to view this watchlist", - "allowed_type_label": "Content Type", - "sort_order_label": "Default Sort Order", - "empty_title": "No Watchlists", - "empty_description": "Create your first watchlist to start organizing your media", - "empty_watchlist": "This watchlist is empty", - "empty_watchlist_hint": "Add items from your library to this watchlist", - "not_configured_title": "Streamystats Not Configured", - "not_configured_description": "Configure Streamystats in settings to use watchlists", - "go_to_settings": "Go to Settings", - "add_to_watchlist": "Add to Watchlist", - "remove_from_watchlist": "Remove from Watchlist", - "select_watchlist": "Select Watchlist", - "create_new": "Create New Watchlist", + "save_button": "Wijzigingen opslaan", + "delete_button": "Verwijder", + "remove_button": "Verwijderen", + "cancel_button": "Annuleren", + "name_label": "Naam", + "name_placeholder": "Voer naam van kijklijst in", + "description_label": "Beschrijving", + "description_placeholder": "Voer beschrijving in (optioneel)", + "is_public_label": "Openbare Kijklijst", + "is_public_description": "Sta anderen toe om deze kijklijst te bekijken", + "allowed_type_label": "Inhoudstype", + "sort_order_label": "Standaard Sortering", + "empty_title": "Geen Kijklijsten", + "empty_description": "Maak je eerste kijklijst om je media te organiseren", + "empty_watchlist": "Deze watchlist is leeg", + "empty_watchlist_hint": "Voeg items uit je bibliotheek toe aan deze kijklijst", + "not_configured_title": "Streamystats niet geconfigureerd", + "not_configured_description": "Configureer Streamystats in instellingen om kijklijsten te gebruiken", + "go_to_settings": "Ga naar Instellingen", + "add_to_watchlist": "Voeg toe aan kijklijst", + "remove_from_watchlist": "Verwijder van kijklijst", + "select_watchlist": "Selecteer kijklijst", + "create_new": "Nieuwe kijklijst aanmaken", "item": "item", "items": "items", - "public": "Public", - "private": "Private", - "you": "You", - "by_owner": "By another user", - "not_found": "Watchlist not found", - "delete_confirm_title": "Delete Watchlist", - "delete_confirm_message": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.", - "remove_item_title": "Remove from Watchlist", - "remove_item_message": "Remove \"{{name}}\" from this watchlist?", - "loading": "Loading watchlists...", - "no_compatible_watchlists": "No compatible watchlists", - "create_one_first": "Create a watchlist that accepts this content type" + "public": "Publiek", + "private": "Privé", + "you": "Jij", + "by_owner": "Door een andere gebruiker", + "not_found": "Kijklijst niet gevonden", + "delete_confirm_title": "Verwijder kijklijst", + "delete_confirm_message": "Weet u zeker dat u \"{{name}}\"wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.", + "remove_item_title": "Verwijder van watchlist", + "remove_item_message": "Verwijder \"{{name}}\" uit deze watchlist?", + "loading": "Laden van watchlists...", + "no_compatible_watchlists": "Geen compatibele watchlist", + "create_one_first": "Maak een watchlist aan die dit inhoudstype accepteert" }, "playback_speed": { - "title": "Playback Speed", - "apply_to": "Apply To", - "speed": "Speed", + "title": "Afspeelsnelheid", + "apply_to": "Toepassen op", + "speed": "Snelheid", "scope": { - "media": "This media only", - "show": "This show", - "all": "All media (default)" + "media": "Alleen deze media", + "show": "Deze serie", + "all": "Alle media (standaard)" } } } diff --git a/translations/ru.json b/translations/ru.json index 17f526d5..a49a5409 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -34,44 +34,44 @@ "search_for_local_servers": "Поиск локальных серверов", "searching": "Поиск...", "servers": "Сервера", - "saved": "Saved", - "session_expired": "Session Expired", - "please_login_again": "Your saved session has expired. Please log in again.", - "remove_saved_login": "Remove Saved Login", - "remove_saved_login_description": "This will remove your saved credentials for this server. You'll need to enter your username and password again next time.", - "accounts_count": "{{count}} accounts", - "select_account": "Select Account", - "add_account": "Add Account", - "remove_account_description": "This will remove the saved credentials for {{username}}." + "saved": "Сохранено", + "session_expired": "Сессия истекла", + "please_login_again": "Ваша сессия истекла. Пожалуйста, войдите снова.", + "remove_saved_login": "Удалить сохраненный аккаунт", + "remove_saved_login_description": "Ваши сохранённые данные для входа от этого сервера будут удалены. Вам придётся ввести ваши логин и пароль ещё раз.", + "accounts_count": "{{count}} аккаунтов", + "select_account": "Выбрать аккаунт", + "add_account": "Добавить аккаунт", + "remove_account_description": "Данные для входа {{username}} будут удалены." }, "save_account": { - "title": "Save Account", - "save_for_later": "Save this account", - "security_option": "Security Option", - "no_protection": "No protection", - "no_protection_desc": "Quick login without authentication", - "pin_code": "PIN code", - "pin_code_desc": "4-digit PIN required when switching", - "password": "Re-enter password", - "password_desc": "Password required when switching", - "save_button": "Save", - "cancel_button": "Cancel" + "title": "Сохранить аккаунт", + "save_for_later": "Сохранить этот аккаунт", + "security_option": "Опции безопасности", + "no_protection": "Без защиты", + "no_protection_desc": "Быстрый вход без ввода данных", + "pin_code": "PIN-код", + "pin_code_desc": "При переключении будет требоваться 4-значный PIN", + "password": "Пароль", + "password_desc": "При переключении будет требоваться пароль", + "save_button": "Сохранить", + "cancel_button": "Отмена" }, "pin": { - "enter_pin": "Enter PIN", - "enter_pin_for": "Enter PIN for {{username}}", - "enter_4_digits": "Enter 4 digits", - "invalid_pin": "Invalid PIN", - "setup_pin": "Set Up PIN", - "confirm_pin": "Confirm PIN", - "pins_dont_match": "PINs don't match", - "forgot_pin": "Forgot PIN?", - "forgot_pin_desc": "Your saved credentials will be removed" + "enter_pin": "Введите PIN", + "enter_pin_for": "Введите PIN для {{username}}", + "enter_4_digits": "Введите 4 цифры", + "invalid_pin": "Некорректный PIN", + "setup_pin": "Установить PIN", + "confirm_pin": "Подтвердите PIN", + "pins_dont_match": "PIN-коды не совпадают", + "forgot_pin": "Забыли PIN?", + "forgot_pin_desc": "Ваши данные для входа будут удалены" }, "password": { - "enter_password": "Enter Password", - "enter_password_for": "Enter password for {{username}}", - "invalid_password": "Invalid password" + "enter_password": "Введите пароль", + "enter_password_for": "Введите пароль для {{username}}", + "invalid_password": "Неверный пароль" }, "home": { "checking_server_connection": "Проверка соединения с сервером...", @@ -82,12 +82,12 @@ "go_to_downloads": "В загрузки", "retry": "Повторить", "server_unreachable": "Сервер недоступен", - "server_unreachable_message": "Could not reach the server.\nPlease check your network connection.", + "server_unreachable_message": "Не удалось соединиться с сервером.\nПожалуйста, проверьте настройки сети.", "oops": "Упс!", "error_message": "Что-то пошло не так.\nПожалуйста выйдите и зайдите снова.", - "continue_watching": "Продолжить просмотр", - "next_up": "Следующее", - "continue_and_next_up": "Continue & Next Up", + "continue_watching": "Продолжить", + "next_up": "Далее", + "continue_and_next_up": "Продолжить и Далее", "recently_added_in": "Недавно добавлено в {{libraryName}}", "suggested_movies": "Предложенные фильмы", "suggested_episodes": "Предложенные серии", @@ -110,46 +110,46 @@ "settings_title": "Настройки", "log_out_button": "Выйти", "categories": { - "title": "Categories" + "title": "Категории" }, "playback_controls": { - "title": "Playback & Controls" + "title": "Воспроизведение и управление" }, "audio_subtitles": { - "title": "Audio & Subtitles" + "title": "Аудио и субтитры" }, "appearance": { - "title": "Appearance", - "merge_next_up_continue_watching": "Merge Continue Watching & Next Up", - "hide_remote_session_button": "Hide Remote Session Button" + "title": "Внешний вид", + "merge_next_up_continue_watching": "Объединить «Продолжить» и «Далее»", + "hide_remote_session_button": "Скрыть кнопку «Удалённый сеанс»" }, "network": { - "title": "Network", - "local_network": "Local Network", - "auto_switch_enabled": "Auto-switch when at home", - "auto_switch_description": "Automatically switch to local URL when connected to home WiFi", - "local_url": "Local URL", - "local_url_hint": "Enter your local server address (e.g., http://192.168.1.100:8096)", + "title": "Сеть", + "local_network": "Локальная сеть", + "auto_switch_enabled": "Переключаться дома автоматически", + "auto_switch_description": "Автоматически переключаться на локальный URL при присоединении к домашней WiFi сети", + "local_url": "Локальный URL", + "local_url_hint": "Введите локальный URL вашего сервера (e.g., http://192.168.1.100:8096)", "local_url_placeholder": "http://192.168.1.100:8096", - "home_wifi_networks": "Home WiFi Networks", - "add_current_network": "Add \"{{ssid}}\"", - "not_connected_to_wifi": "Not connected to WiFi", - "no_networks_configured": "No networks configured", - "add_network_hint": "Add your home WiFi network to enable auto-switching", - "current_wifi": "Current WiFi", - "using_url": "Using", - "local": "Local URL", - "remote": "Remote URL", - "not_connected": "Not connected", - "current_server": "Current Server", - "remote_url": "Remote URL", - "active_url": "Active URL", - "not_configured": "Not configured", - "network_added": "Network added", - "network_already_added": "Network already added", - "no_wifi_connected": "Not connected to WiFi", - "permission_denied": "Location permission denied", - "permission_denied_explanation": "Location permission is required to detect WiFi network for auto-switching. Please enable it in Settings." + "home_wifi_networks": "Домашние WiFi сети", + "add_current_network": "Добавить \"{{ssid}}\"", + "not_connected_to_wifi": "Нет WiFi соединения", + "no_networks_configured": "Нет настроенных сетей", + "add_network_hint": "Добавьте вашу домашнюю сеть WiFi для включения автоматического переключения", + "current_wifi": "Текущая WiFi сеть", + "using_url": "Используется", + "local": "Локальный", + "remote": "Внешний", + "not_connected": "Нет соединения", + "current_server": "Текущий сервер", + "remote_url": "Внешний URL", + "active_url": "Активный URL", + "not_configured": "Не настроено", + "network_added": "Сеть добавлена", + "network_already_added": "Сеть уже добавлена", + "no_wifi_connected": "Нет WiFi соединения", + "permission_denied": "Нет доступа к местоположению", + "permission_denied_explanation": "Разрешение на доступ к местоположению обязательно для обнаружения WiFi сети при автоматическом переключении. Пожалуйста, включите его в настройках." }, "user_info": { "user_info_title": "Информация о пользователе", @@ -170,22 +170,22 @@ }, "media_controls": { "media_controls_title": "Медиа-контроль", - "forward_skip_length": "Длина пропуска вперед", - "rewind_length": "Длина перемотки", + "forward_skip_length": "Шаг перемотки вперёд", + "rewind_length": "Шаг перемотки назад", "seconds_unit": "c" }, "gesture_controls": { "gesture_controls_title": "Управление жестами", - "horizontal_swipe_skip": "Горизонтальный свайп, чтобы пропустить", + "horizontal_swipe_skip": "Горизонтальный свайп для перемотки", "horizontal_swipe_skip_description": "Проведите влево/вправо, когда элементы управления скрыты, чтобы пропустить", "left_side_brightness": "Управление яркостью левой стороны", "left_side_brightness_description": "Смахните вверх/вниз на левой стороне для настройки яркости", "right_side_volume": "Управление громкостью справа", "right_side_volume_description": "Свайп вверх/вниз с правой стороны для настройки громкости", - "hide_volume_slider": "Hide Volume Slider", - "hide_volume_slider_description": "Hide the volume slider in the video player", - "hide_brightness_slider": "Hide Brightness Slider", - "hide_brightness_slider_description": "Hide the brightness slider in the video player" + "hide_volume_slider": "Скрыть индикатор громкости", + "hide_volume_slider_description": "Скрывает индикатор громкости в плеере", + "hide_brightness_slider": "Скрыть индикатор яркости", + "hide_brightness_slider_description": "Скрывает индикатор яркости в плеере" }, "audio": { "audio_title": "Аудио", @@ -195,17 +195,17 @@ "none": "Отсутствует", "language": "Язык", "transcode_mode": { - "title": "Audio Transcoding", - "description": "Controls how surround audio (7.1, TrueHD, DTS-HD) is handled", - "auto": "Auto", - "stereo": "Force Stereo", - "5_1": "Allow 5.1", - "passthrough": "Passthrough" + "title": "Перекодировка аудио", + "description": "Управляет обработкой пространственного звука (7.1, TrueHD, DTS-HD)", + "auto": "Авто", + "stereo": "Принудительно в стерео", + "5_1": "Разрешить 5.1", + "passthrough": "Ничего не изменять" } }, "subtitles": { "subtitle_title": "Субтитры", - "subtitle_hint": "Настроить субтитры.", + "subtitle_hint": "Настройки отображения субтитров", "subtitle_language": "Язык субтитров", "subtitle_mode": "Режим субтитров", "set_subtitle_track": "Устанавливать субтитры из предыдущего элемента", @@ -226,24 +226,24 @@ "outline_thickness": "Толщина контура", "background_opacity": "Прозрачность фона", "outline_opacity": "Прозрачность контура", - "bold_text": "Bold Text", + "bold_text": "Жирный", "colors": { "Black": "Черный", "Gray": "Серый", - "Silver": "Серебряный", + "Silver": "Серебристый", "White": "Белый", - "Maroon": "Марун", + "Maroon": "Бордовый", "Red": "Красный", - "Fuchsia": "Fuchsia", + "Fuchsia": "Пурпурный", "Yellow": "Жёлтый", - "Olive": "Олив", + "Olive": "Оливковый", "Green": "Зелёный", "Teal": "Бирюзовый", "Lime": "Лаймовый", "Purple": "Фиолетовый", "Navy": "Тёмно-синий", "Blue": "Синий", - "Aqua": "Акваа" + "Aqua": "Голубой" }, "thickness": { "None": "Отсутствует", @@ -251,29 +251,29 @@ "Normal": "Обычный", "Thick": "Толстый" }, - "subtitle_color": "Subtitle Color", - "subtitle_background_color": "Background Color", - "subtitle_font": "Subtitle Font", - "ksplayer_title": "KSPlayer Settings", - "hardware_decode": "Hardware Decoding", - "hardware_decode_description": "Use hardware acceleration for video decoding. Disable if you experience playback issues." + "subtitle_color": "Цвет субтитров", + "subtitle_background_color": "Цвет фона", + "subtitle_font": "Шрифт субтитров", + "ksplayer_title": "Настройки KSPlayer", + "hardware_decode": "Аппаратное декодирование", + "hardware_decode_description": "Использовать аппаратное ускорение для декодирования видео. Выключите, если наблюдаете проблемы с воспроизведением." }, "vlc_subtitles": { - "title": "VLC Subtitle Settings", - "hint": "Customize subtitle appearance for VLC player. Changes take effect on next playback.", - "text_color": "Text Color", - "background_color": "Background Color", - "background_opacity": "Background Opacity", - "outline_color": "Outline Color", - "outline_opacity": "Outline Opacity", - "outline_thickness": "Outline Thickness", - "bold": "Bold Text", - "margin": "Bottom Margin" + "title": "Настройки субтитров в VLC", + "hint": "Настройте внешний вид субтитров в VLC плеере. Изменения применятся при следующем воспроизведении.", + "text_color": "Цвет текста", + "background_color": "Цвет фона", + "background_opacity": "Прозрачность фона", + "outline_color": "Цвет контура", + "outline_opacity": "Прозрачность контура", + "outline_thickness": "Толщина контура", + "bold": "Жирный", + "margin": "Отступ снизу" }, "video_player": { - "title": "Video Player", - "video_player": "Video Player", - "video_player_description": "Choose which video player to use on iOS.", + "title": "Видеоплеер", + "video_player": "Видеоплеер", + "video_player_description": "Выберите видеоплеер в iOS.", "ksplayer": "KSPlayer", "vlc": "VLC" }, @@ -294,19 +294,19 @@ "UNKNOWN": "Неизвестное" }, "safe_area_in_controls": "Безопасная зона в элементах управления", - "video_player": "Видео прейер", + "video_player": "Видеоплеер", "video_players": { "VLC_3": "VLC 3", "VLC_4": "VLC 4 (Экспериментальный + PiP)" }, "show_custom_menu_links": "Показать ссылки кастомного меню", - "show_large_home_carousel": "Show Large Home Carousel (beta)", + "show_large_home_carousel": "Показывать большую карусель (beta)", "hide_libraries": "Скрыть библиотеки", "select_liraries_you_want_to_hide": "Выберите Библиотеки, которое хотите спрятать из вкладки Библиотеки и домашней страницы.", "disable_haptic_feedback": "Отключить тактильную обратную связь", "default_quality": "Качество по умолчанию", - "default_playback_speed": "Default Playback Speed", - "auto_play_next_episode": "Auto-play Next Episode", + "default_playback_speed": "Скорость воспроизведения по умолчанию", + "auto_play_next_episode": "Автоматически воспроизводить следующий эпизод", "max_auto_play_episode_count": "Максимальное количество автовоспроизведения эпизодов", "disabled": "Отключено" }, @@ -314,15 +314,15 @@ "downloads_title": "Загрузки" }, "music": { - "title": "Music", - "playback_title": "Playback", - "playback_description": "Configure how music is played.", - "prefer_downloaded": "Prefer Downloaded Songs", - "caching_title": "Caching", - "caching_description": "Automatically cache upcoming tracks for smoother playback.", - "lookahead_enabled": "Enable Look-Ahead Caching", - "lookahead_count": "Tracks to Pre-cache", - "max_cache_size": "Max Cache Size" + "title": "Музыка", + "playback_title": "Воспроизведение", + "playback_description": "Настройте воспроизведение музыки.", + "prefer_downloaded": "Предпочитать скачанные песни", + "caching_title": "Кеширование", + "caching_description": "Автоматически предкешировать следующие треки для стабильного воспроизведения.", + "lookahead_enabled": "Включить предкеширование", + "lookahead_count": "Сколько предкешировать", + "max_cache_size": "Максимальное число предкешированных треков" }, "plugins": { "plugins_title": "Плагины", @@ -357,39 +357,39 @@ "save_button": "Сохранить", "toasts": { "saved": "Сохранено", - "refreshed": "Settings refreshed from server" + "refreshed": "Настройки обновлены с сервера" }, - "refresh_from_server": "Refresh Settings from Server" + "refresh_from_server": "Обновить настройки с сервера" }, "streamystats": { - "enable_streamystats": "Enable Streamystats", - "disable_streamystats": "Disable Streamystats", - "enable_search": "Use for Search", + "enable_streamystats": "Включить Streamystats", + "disable_streamystats": "Выключить Streamystats", + "enable_search": "Использовать в поиске", "url": "URL", "server_url_placeholder": "http(s)://streamystats.example.com", - "streamystats_search_hint": "Enter the URL for your Streamystats server. The URL should include http or https and optionally the port.", - "read_more_about_streamystats": "Read More About Streamystats.", - "save_button": "Save", - "save": "Save", - "features_title": "Features", - "home_sections_title": "Home Sections", - "enable_movie_recommendations": "Movie Recommendations", - "enable_series_recommendations": "Series Recommendations", - "enable_promoted_watchlists": "Promoted Watchlists", - "hide_watchlists_tab": "Hide Watchlists Tab", - "home_sections_hint": "Show personalized recommendations and promoted watchlists from Streamystats on the home page.", - "recommended_movies": "Recommended Movies", - "recommended_series": "Recommended Series", + "streamystats_search_hint": "Введите URL вашего сервера Streamystats. URL должен включать http/https и порт при необходимости.", + "read_more_about_streamystats": "Узнать больше про Streamystats.", + "save_button": "Сохранить", + "save": "Сохранить", + "features_title": "Функции", + "home_sections_title": "Показывать на главной", + "enable_movie_recommendations": "Рекомендации фильмов", + "enable_series_recommendations": "Рекомендации сериалов", + "enable_promoted_watchlists": "Продвигаемые списки просмотра", + "hide_watchlists_tab": "Скрыть вкладку со списками", + "home_sections_hint": "Показывать персонализированные рекомендации и подходящие списки просмотров из Streamystats на главной странице.", + "recommended_movies": "Рекомендованные фильмы", + "recommended_series": "Рекомендованные сериалы", "toasts": { - "saved": "Saved", - "refreshed": "Settings refreshed from server", - "disabled": "Streamystats disabled" + "saved": "Сохранено", + "refreshed": "Настройки обновлены с сервера", + "disabled": "Streamystats отключен" }, - "refresh_from_server": "Refresh Settings from Server" + "refresh_from_server": "Обновить настройки с сервера" }, "kefinTweaks": { - "watchlist_enabler": "Enable our Watchlist integration", - "watchlist_button": "Toggle Watchlist integration" + "watchlist_enabler": "Включить интеграцию со списками просмотра", + "watchlist_button": "Изменить интеграцию со списками просмотра" } }, "storage": { @@ -398,18 +398,18 @@ "device_usage": "Устройство {{availableSpace}}%", "size_used": "{{used}} из {{total}} использовано", "delete_all_downloaded_files": "Удалить все загруженные файлы", - "music_cache_title": "Music Cache", - "music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support", - "enable_music_cache": "Enable Music Cache", - "clear_music_cache": "Clear Music Cache", - "music_cache_size": "{{size}} cached", - "music_cache_cleared": "Music cache cleared", - "delete_all_downloaded_songs": "Delete All Downloaded Songs", - "downloaded_songs_size": "{{size}} downloaded", - "downloaded_songs_deleted": "Downloaded songs deleted" + "music_cache_title": "Кеш музыки", + "music_cache_description": "Автоматически прекешировать песни по мере прослушивания для плавного воспроизведения и поддержки отсутствия интернета", + "enable_music_cache": "Кешировать музыку", + "clear_music_cache": "Очистить кеш музыки", + "music_cache_size": "{{size}} кешировано", + "music_cache_cleared": "Кеш музыки очищен", + "delete_all_downloaded_songs": "Удалить все скачанные песни", + "downloaded_songs_size": "{{size}} скачано", + "downloaded_songs_deleted": "Скачанные песни удалены" }, "intro": { - "title": "Intro", + "title": "Вступление", "show_intro": "Показать вступление", "reset_intro": "Сбросить вступление" }, @@ -441,24 +441,24 @@ "tvseries": "Сериалы", "movies": "Фильмы", "queue": "Очередь", - "other_media": "Другие медиа", - "queue_hint": "Очередь и загрузки будут удалены при перезагрузке приложения", + "other_media": "Прочие файлы", + "queue_hint": "Очередь очистится после перезапуска", "no_items_in_queue": "Нет элементов в очереди", - "no_downloaded_items": "Нет загруженых предметов", + "no_downloaded_items": "Нет загруженных файлов", "delete_all_movies_button": "Удалить все фильмы", "delete_all_tvseries_button": "Удалить все сериалы", "delete_all_button": "Удалить все", - "delete_all_other_media_button": "Удалить другой материал", - "active_download": "Активно загружается", + "delete_all_other_media_button": "Удалить прочие файлы", + "active_download": "Загружается", "no_active_downloads": "Нет активных загрузок", - "active_downloads": "Активные загрузки", + "active_downloads": "Активные", "new_app_version_requires_re_download": "Новая версия приложения требует повторной загрузки", "new_app_version_requires_re_download_description": "Новая версия приложения требует повторной загрузки. Пожалуйста удалите всё и попробуйте заново.", "back": "Назад", "delete": "Удалить", "something_went_wrong": "Что-то пошло не так", "could_not_get_stream_url_from_jellyfin": "Не удалось получить ссылку трансляции из Jellyfin", - "eta": "ETA {{eta}}", + "eta": "Осталось {{eta}}", "toasts": { "you_are_not_allowed_to_download_files": "Нет разрешения на скачивание файлов.", "deleted_all_movies_successfully": "Все фильмы были успешно удалены!", @@ -467,64 +467,64 @@ "failed_to_delete_all_tvseries": "Возникла ошибка при удалении всех сериалов", "deleted_media_successfully": "Другие носители успешно удалены!", "failed_to_delete_media": "Не удалось удалить другой файл", - "download_deleted": "Загрузка удалена", + "download_deleted": "Удалено", "download_cancelled": "Загрузка отменена", "could_not_delete_download": "Не удалось удалить загрузку", - "download_paused": "Загрузка приостановлена", + "download_paused": "На паузе", "could_not_pause_download": "Не удалось приостановить загрузку", - "download_resumed": "Загрузка возобновлена", + "download_resumed": "Продолжено", "could_not_resume_download": "Не удалось продолжить загрузку", - "download_completed": "Загрузка завершена", - "download_failed": "Download Failed", + "download_completed": "Завершено", + "download_failed": "Не удалось загрузить", "download_failed_for_item": "Загрузка {{item}} провалилась с ошибкой: {{error}}", "download_completed_for_item": "{{item}} успешно загружен", "download_started_for_item": "Загрузка началась для {{item}}", "failed_to_start_download": "Не удалось начать загрузку", - "item_already_downloading": "{{item}} is already downloading", - "all_files_deleted": "All Downloads Deleted Successfully", - "files_deleted_by_type": "{{count}} {{type}} deleted", + "item_already_downloading": "{{item}} уже загружается", + "all_files_deleted": "Все загрузки удалены", + "files_deleted_by_type": "{{count}} {{type}} удалён(о)", "all_files_folders_and_jobs_deleted_successfully": "Все файлы, папки, и задачи были успешно удалены", "failed_to_clean_cache_directory": "Не удалось очистить директорию кэша", "could_not_get_download_url_for_item": "Не удалось получить URL загрузки для {{itemName}}", "go_to_downloads": "В загрузки", - "file_deleted": "{{item}} deleted" + "file_deleted": "{{item}} удалён" } } }, "common": { "select": "Выбрать", - "no_trailer_available": "Прицеп недоступен", + "no_trailer_available": "Трейлер недоступен", "video": "Видео", "audio": "Звук", "subtitle": "Субтитры", - "play": "Играть", - "none": "None", - "track": "Track", - "cancel": "Cancel", - "delete": "Delete", - "ok": "OK", - "remove": "Remove", - "next": "Next", - "back": "Back", - "continue": "Continue", - "verifying": "Verifying..." + "play": "Воспроизвести", + "none": "Отсутствует", + "track": "Трек", + "cancel": "Отмена", + "delete": "Удалить", + "ok": "ОК", + "remove": "Удалить", + "next": "Вперед", + "back": "Назад", + "continue": "Продолжить", + "verifying": "Проверка..." }, "search": { "search": "Поиск...", - "x_items": "{{count}} предметов", + "x_items": "{{count}} элементов", "library": "Библиотека", "discover": "Найти новое", - "no_results": "Нет результатов", - "no_results_found_for": "Не было результатов при поиске", + "no_results": "Ничего не найдено", + "no_results_found_for": "Ничего не найдено по запросу", "movies": "Фильмы", "series": "Сериалы", "episodes": "Серии", "collections": "Коллекции", "actors": "Актеры", - "artists": "Artists", - "albums": "Albums", - "songs": "Songs", - "playlists": "Playlists", + "artists": "Артисты", + "albums": "Альбомы", + "songs": "Песни", + "playlists": "Плейлисты", "request_movies": "Запросить фильмы", "request_series": "Запросить сериалы", "recently_added": "Недавно добавлено", @@ -553,7 +553,7 @@ "no_results": "Нет результатов", "no_libraries_found": "Библиотеки не найдены", "item_types": { - "movies": "фильмы", + "movies": "Фильмы", "series": "Сериалы", "boxsets": "Коллекции", "items": "элементы" @@ -571,9 +571,9 @@ "filters": { "genres": "Жанры", "years": "Года", - "sort_by": "Сортировать по", - "filter_by": "Filter By", - "sort_order": "Порядок сортировки", + "sort_by": "Сортировка", + "filter_by": "Фильтр", + "sort_order": "Порядок", "tags": "Тэги" } }, @@ -604,14 +604,14 @@ "index": "Индекс:", "continue_watching": "Продолжить просмотр", "go_back": "Назад", - "downloaded_file_title": "You have this file downloaded", - "downloaded_file_message": "Do you want to play the downloaded file?", - "downloaded_file_yes": "Yes", - "downloaded_file_no": "No", - "downloaded_file_cancel": "Cancel" + "downloaded_file_title": "Этот файл уже скачан", + "downloaded_file_message": "Хотите воспроизвести скачанный файл?", + "downloaded_file_yes": "Да", + "downloaded_file_no": "Нет", + "downloaded_file_cancel": "Отмена" }, "item_card": { - "next_up": "Следующее", + "next_up": "Далее", "no_items_to_display": "Нет элементов для отображения", "cast_and_crew": "Актеры и съемочная группа", "series": "Серии", @@ -644,7 +644,7 @@ } }, "live_tv": { - "next": "Следующая", + "next": "Далее", "previous": "Предыдущая", "coming_soon": "Скоро", "on_now": "Сейчас в эфире", @@ -675,7 +675,7 @@ "series_type": "Тип сериала", "release_dates": "Дата релиза", "first_air_date": "Первая дата выхода в эфир", - "next_air_date": "Следующая дата выхода в эфир", + "next_air_date": "Ближайшая дата выхода в эфир", "revenue": "Прибыль", "budget": "Бюджет", "original_language": "Оригинальный язык", @@ -693,10 +693,10 @@ "number_episodes": "{{episode_number}} серий", "born": "Рожден", "appearances": "Появления", - "approve": "Approve", - "decline": "Decline", - "requested_by": "Requested by {{user}}", - "unknown_user": "Unknown User", + "approve": "Одобрить", + "decline": "Отклонить", + "requested_by": "Запрошено {{user}}", + "unknown_user": "Неизвестный пользователь", "toasts": { "jellyseer_does_not_meet_requirements": "Сервер Jellyseerr не соответствует минимальным требованиям версии! Пожалуйста, обновите до версии не ниже 2.0.0", "jellyseerr_test_failed": "Тест Jellyseerr не пройден. Попробуйте еще раз.", @@ -705,141 +705,141 @@ "requested_item": "Запрошено {{item}}!", "you_dont_have_permission_to_request": "У вас нет разрешения на запрос!", "something_went_wrong_requesting_media": "Что-то пошло не так при запросе медиафайлов!", - "request_approved": "Request Approved!", - "request_declined": "Request Declined!", - "failed_to_approve_request": "Failed to Approve Request", - "failed_to_decline_request": "Failed to Decline Request" + "request_approved": "Запрос одобрен!", + "request_declined": "Запрос отклонён!", + "failed_to_approve_request": "Не удалось одобрить запрос", + "failed_to_decline_request": "Не удалось отклонить запрос" } }, "tabs": { - "home": "Дом", + "home": "Главная", "search": "Поиск", "library": "Библиотека", - "custom_links": "Кастомные ссылки", + "custom_links": "Ссылки", "favorites": "Избранное" }, "music": { - "title": "Music", + "title": "Музыка", "tabs": { - "suggestions": "Suggestions", - "albums": "Albums", - "artists": "Artists", - "playlists": "Playlists", - "tracks": "tracks" + "suggestions": "Рекомендации", + "albums": "Альбомы", + "artists": "Исполнители", + "playlists": "Плейлисты", + "tracks": "треки" }, "filters": { - "all": "All" + "all": "Все" }, - "recently_added": "Recently Added", - "recently_played": "Recently Played", - "frequently_played": "Frequently Played", - "explore": "Explore", - "top_tracks": "Top Tracks", - "play": "Play", - "shuffle": "Shuffle", - "play_top_tracks": "Play Top Tracks", - "no_suggestions": "No suggestions available", - "no_albums": "No albums found", - "no_artists": "No artists found", - "no_playlists": "No playlists found", - "album_not_found": "Album not found", - "artist_not_found": "Artist not found", - "playlist_not_found": "Playlist not found", + "recently_added": "Недавно добавлено", + "recently_played": "Недавно воспроизведено", + "frequently_played": "Часто играет", + "explore": "Найти новое", + "top_tracks": "Топ", + "play": "Воспроизвести", + "shuffle": "Перемешать", + "play_top_tracks": "Воспроизвести топ", + "no_suggestions": "Нет рекомендаций", + "no_albums": "Альбомы не найдены", + "no_artists": "Исполнители не найдены", + "no_playlists": "Плейлисты не найдены", + "album_not_found": "Альбом не найден", + "artist_not_found": "Исполнитель не найден", + "playlist_not_found": "Плейлист не найден", "track_options": { - "play_next": "Play Next", - "add_to_queue": "Add to Queue", - "add_to_playlist": "Add to Playlist", - "download": "Download", - "downloaded": "Downloaded", - "downloading": "Downloading...", - "cached": "Cached", - "delete_download": "Delete Download", - "delete_cache": "Remove from Cache", - "go_to_artist": "Go to Artist", - "go_to_album": "Go to Album", - "add_to_favorites": "Add to Favorites", - "remove_from_favorites": "Remove from Favorites", - "remove_from_playlist": "Remove from Playlist" + "play_next": "Далее", + "add_to_queue": "Добавить в очередь", + "add_to_playlist": "Добавить в плейлист", + "download": "Скачать", + "downloaded": "Скачано", + "downloading": "Скачивается...", + "cached": "Кешировано", + "delete_download": "Удалить загрузку", + "delete_cache": "Удалить из кеша", + "go_to_artist": "К исполнителю", + "go_to_album": "К альбому", + "add_to_favorites": "В избранное", + "remove_from_favorites": "Удалить из избранного", + "remove_from_playlist": "Удалить из плейлиста" }, "playlists": { - "create_playlist": "Create Playlist", - "playlist_name": "Playlist Name", - "enter_name": "Enter playlist name", - "create": "Create", - "search_playlists": "Search playlists...", - "added_to": "Added to {{name}}", - "added": "Added to playlist", - "removed_from": "Removed from {{name}}", - "removed": "Removed from playlist", - "created": "Playlist created", - "create_new": "Create New Playlist", - "failed_to_add": "Failed to add to playlist", - "failed_to_remove": "Failed to remove from playlist", - "failed_to_create": "Failed to create playlist", - "delete_playlist": "Delete Playlist", - "delete_confirm": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.", - "deleted": "Playlist deleted", - "failed_to_delete": "Failed to delete playlist" + "create_playlist": "Создать плейлист", + "playlist_name": "Название плейлиста", + "enter_name": "Введите название плейлиста", + "create": "Создать", + "search_playlists": "Поиск плейлистов...", + "added_to": "Добавлено в {{name}}", + "added": "Добавлено в плейлист", + "removed_from": "Удалено из {{name}}", + "removed": "Удалено из плейлиста", + "created": "Плейлист создан", + "create_new": "Добавить новый плейлист", + "failed_to_add": "Не удалось добавить в плейлист", + "failed_to_remove": "Не удалось удалить из плейлиста", + "failed_to_create": "Не удалось создать плейлист", + "delete_playlist": "Удалить плейлист", + "delete_confirm": "Вы уверены, что хотите удалить \"{{name}}\"? Это действие необратимо.", + "deleted": "Плейлист удалён", + "failed_to_delete": "Не удалось удалить плейлист" }, "sort": { - "title": "Sort By", - "alphabetical": "Alphabetical", - "date_created": "Date Created" + "title": "Сортировка", + "alphabetical": "По алфавиту", + "date_created": "По дате создания" } }, "watchlists": { - "title": "Watchlists", - "my_watchlists": "My Watchlists", - "public_watchlists": "Public Watchlists", - "create_title": "Create Watchlist", - "edit_title": "Edit Watchlist", - "create_button": "Create Watchlist", - "save_button": "Save Changes", - "delete_button": "Delete", - "remove_button": "Remove", - "cancel_button": "Cancel", - "name_label": "Name", - "name_placeholder": "Enter watchlist name", - "description_label": "Description", - "description_placeholder": "Enter description (optional)", - "is_public_label": "Public Watchlist", - "is_public_description": "Allow others to view this watchlist", - "allowed_type_label": "Content Type", - "sort_order_label": "Default Sort Order", - "empty_title": "No Watchlists", - "empty_description": "Create your first watchlist to start organizing your media", - "empty_watchlist": "This watchlist is empty", - "empty_watchlist_hint": "Add items from your library to this watchlist", - "not_configured_title": "Streamystats Not Configured", - "not_configured_description": "Configure Streamystats in settings to use watchlists", - "go_to_settings": "Go to Settings", - "add_to_watchlist": "Add to Watchlist", - "remove_from_watchlist": "Remove from Watchlist", - "select_watchlist": "Select Watchlist", - "create_new": "Create New Watchlist", - "item": "item", - "items": "items", - "public": "Public", - "private": "Private", - "you": "You", - "by_owner": "By another user", - "not_found": "Watchlist not found", - "delete_confirm_title": "Delete Watchlist", - "delete_confirm_message": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.", - "remove_item_title": "Remove from Watchlist", - "remove_item_message": "Remove \"{{name}}\" from this watchlist?", - "loading": "Loading watchlists...", - "no_compatible_watchlists": "No compatible watchlists", - "create_one_first": "Create a watchlist that accepts this content type" + "title": "Списки просмотров", + "my_watchlists": "Мои списки", + "public_watchlists": "Публичные списки", + "create_title": "Создать список", + "edit_title": "Редактировать список", + "create_button": "Создать список", + "save_button": "Сохранить изменения", + "delete_button": "Удалить", + "remove_button": "Удалить", + "cancel_button": "Отмена", + "name_label": "Название", + "name_placeholder": "Введите название списка", + "description_label": "Описание", + "description_placeholder": "Введите описание (не обязательно)", + "is_public_label": "Публичный", + "is_public_description": "Разрешить остальным пользователям видеть этот список", + "allowed_type_label": "Тип контента", + "sort_order_label": "Сортировка по умолчанию", + "empty_title": "Нет списков", + "empty_description": "Создайте ваш первый список для управления вашими медиа", + "empty_watchlist": "Этот список пуст", + "empty_watchlist_hint": "Добавляйте элементы из библиотеки в этот список", + "not_configured_title": "Streamystats не настроен", + "not_configured_description": "Настройте Streamystats для использования функционала списков", + "go_to_settings": "В настройки", + "add_to_watchlist": "Добавить в список просмотра", + "remove_from_watchlist": "Удалить из списка просмотра", + "select_watchlist": "Выбрать список", + "create_new": "Создать новый список", + "item": "элемент", + "items": "элементы", + "public": "Публичный", + "private": "Личный", + "you": "Ваш", + "by_owner": "Другим пользователем", + "not_found": "Список не найден", + "delete_confirm_title": "Удалить список", + "delete_confirm_message": "Вы уверены, что хотите удалить список \"{{name}}\"? Это действие необратимо.", + "remove_item_title": "Удалить из списка", + "remove_item_message": "Удалить \"{{name}}\" из списка?", + "loading": "Загрузка списков...", + "no_compatible_watchlists": "Нет совместимых списков", + "create_one_first": "Создайте список просмотра с подходящим типом контента" }, "playback_speed": { - "title": "Playback Speed", - "apply_to": "Apply To", - "speed": "Speed", + "title": "Скорость воспроизведения", + "apply_to": "Применять к", + "speed": "Скорость", "scope": { - "media": "This media only", - "show": "This show", - "all": "All media (default)" + "media": "Только в этот раз", + "show": "Ко всему сериалу", + "all": "Ко всем файлам (по умолчанию)" } } } diff --git a/translations/tr.json b/translations/tr.json index 15bbebf8..667c2039 100644 --- a/translations/tr.json +++ b/translations/tr.json @@ -7,88 +7,88 @@ "username_placeholder": "Kullanıcı adı", "password_placeholder": "Şifre", "login_button": "Giriş yap", - "quick_connect": "Hızlı Bağlantı", + "quick_connect": "Hızlı Bağlan", "enter_code_to_login": "Giriş yapmak için {{code}} kodunu girin", - "failed_to_initiate_quick_connect": "Quick Connect başlatılamadı", + "failed_to_initiate_quick_connect": "Hızlı Bağlan başlatılamadı", "got_it": "Anlaşıldı", "connection_failed": "Bağlantı başarısız", - "could_not_connect_to_server": "Sunucuya bağlanılamadı. Lütfen URL'yi ve ağ bağlantınızı kontrol edin", + "could_not_connect_to_server": "Sunucuya bağlanılamadı. Lütfen URL'yi ve ağ bağlantınızı kontrol edin.", "an_unexpected_error_occured": "Beklenmedik bir hata oluştu", - "change_server": "Sunucuyu değiştir", + "change_server": "Sunucu değiştir", "invalid_username_or_password": "Geçersiz kullanıcı adı veya şifre", "user_does_not_have_permission_to_log_in": "Kullanıcının giriş yapma izni yok", - "server_is_taking_too_long_to_respond_try_again_later": "Sunucu yanıt vermekte çok uzun sürüyor, lütfen tekrar deneyin", - "server_received_too_many_requests_try_again_later": "Sunucu çok fazla istek aldı, lütfen tekrar deneyin.", + "server_is_taking_too_long_to_respond_try_again_later": "Sunucunun yanıt vermesi çok uzun sürüyor, lütfen daha sonra tekrar deneyin", + "server_received_too_many_requests_try_again_later": "Sunucu çok fazla istek aldı, lütfen daha sonra tekrar deneyin.", "there_is_a_server_error": "Sunucu hatası var", - "an_unexpected_error_occured_did_you_enter_the_correct_url": "Beklenmedik bir hata oluştu. Sunucu URL'sini doğru girdiğinizden emin oldunuz mu?", - "too_old_server_text": "Unsupported Jellyfin Server Discovered", - "too_old_server_description": "Please update Jellyfin to the latest version" + "an_unexpected_error_occured_did_you_enter_the_correct_url": "Beklenmedik bir hata oluştu. Sunucu URL'sini doğru girdiğinizden emin misiniz?", + "too_old_server_text": "Desteklenmeyen Jellyfin Sunucu sürümü bulundu.", + "too_old_server_description": "Lütfen Jellyfin'i en son sürüme güncelleyin." }, "server": { - "enter_url_to_jellyfin_server": "Jellyfin sunucunusun URL'sini girin", + "enter_url_to_jellyfin_server": "Jellyfin sunucunusun URL adresini girin", "server_url_placeholder": "http(s)://sunucunuz.com", "connect_button": "Bağlan", "previous_servers": "Önceki sunucular", "clear_button": "Temizle", - "swipe_to_remove": "Swipe to remove", + "swipe_to_remove": "Kaldırmak için kaydırın", "search_for_local_servers": "Yerel sunucuları ara", "searching": "Aranıyor...", "servers": "Sunucular", - "saved": "Saved", - "session_expired": "Session Expired", - "please_login_again": "Your saved session has expired. Please log in again.", - "remove_saved_login": "Remove Saved Login", - "remove_saved_login_description": "This will remove your saved credentials for this server. You'll need to enter your username and password again next time.", - "accounts_count": "{{count}} accounts", - "select_account": "Select Account", - "add_account": "Add Account", - "remove_account_description": "This will remove the saved credentials for {{username}}." + "saved": "Kaydedildi", + "session_expired": "Oturum süresi doldu", + "please_login_again": "Kaydedilmiş oturumunuzun süresi doldu. Lütfen tekrar giriş yapın.", + "remove_saved_login": "Kayıtlı oturumu kaldır", + "remove_saved_login_description": "Bu sunucu için kaydedilmiş kimlik bilgileriniz kaldırılacaktır. Bir sonraki sefere kullanıcı adı ve şifrenizi yeniden girmeniz gerekecek.", + "accounts_count": "{{count}} hesap", + "select_account": "Hesap Seç", + "add_account": "Hesap Ekle", + "remove_account_description": "{{username}} için kayıtlı bilgiler kaldırılacaktır." }, "save_account": { - "title": "Save Account", - "save_for_later": "Save this account", - "security_option": "Security Option", + "title": "Hesabı Kaydet", + "save_for_later": "Bu hesabı kaydet", + "security_option": "Güvenlik Seçeneği", "no_protection": "No protection", - "no_protection_desc": "Quick login without authentication", - "pin_code": "PIN code", - "pin_code_desc": "4-digit PIN required when switching", - "password": "Re-enter password", - "password_desc": "Password required when switching", - "save_button": "Save", - "cancel_button": "Cancel" + "no_protection_desc": "Kimlik doğrulamasız hızlı giriş", + "pin_code": "PIN kodu", + "pin_code_desc": "Geçiş yaparken 4 haneli PIN kodu gereklidir", + "password": "Şifrenizi tekrar girin ", + "password_desc": "Geçiş yaparken şifre gereklidir", + "save_button": "Kaydet", + "cancel_button": "Vazgeç" }, "pin": { - "enter_pin": "Enter PIN", - "enter_pin_for": "Enter PIN for {{username}}", - "enter_4_digits": "Enter 4 digits", - "invalid_pin": "Invalid PIN", - "setup_pin": "Set Up PIN", - "confirm_pin": "Confirm PIN", - "pins_dont_match": "PINs don't match", - "forgot_pin": "Forgot PIN?", - "forgot_pin_desc": "Your saved credentials will be removed" + "enter_pin": "PIN kodunu girin", + "enter_pin_for": "{{username}} için PIN kodunu girin", + "enter_4_digits": "4 hane girin", + "invalid_pin": "Geçersiz PIN kodu", + "setup_pin": "PIN kodunu ayarla", + "confirm_pin": "PIN kodunu onayla", + "pins_dont_match": "PIN kodları eşleşmiyor", + "forgot_pin": "PIN kodunu mu unuttunuz?", + "forgot_pin_desc": "Kayıtlı bilgileriniz kaldırılacaktır" }, "password": { - "enter_password": "Enter Password", - "enter_password_for": "Enter password for {{username}}", - "invalid_password": "Invalid password" + "enter_password": "Şifrenizi girin", + "enter_password_for": "{{username}} için şifrenizi girin", + "invalid_password": "Geçersiz şifre" }, "home": { - "checking_server_connection": "Checking server connection...", + "checking_server_connection": "Sunucu bağlantısı kontrol ediliyor...", "no_internet": "İnternet Yok", "no_items": "Öge Yok", - "no_internet_message": "Endişelenmeyin, hala\ndownloaded içerik izleyebilirsiniz.", - "checking_server_connection_message": "Checking connection to server", - "go_to_downloads": "İndirmelere Git", - "retry": "Retry", - "server_unreachable": "Server Unreachable", - "server_unreachable_message": "Could not reach the server.\nPlease check your network connection.", + "no_internet_message": "Endişelenmeyin, indirilmiş içerikleri izleyebilirsiniz.", + "checking_server_connection_message": "Sunucuya bağlantı kontrol ediliyor", + "go_to_downloads": "İndirilenlere git", + "retry": "Tekrar dene", + "server_unreachable": "Sunucuya ulaşılamıyor", + "server_unreachable_message": "Sunucuya bağlanılamadı. Lütfen ağ bağlantınızı kontrol edin.", "oops": "Hups!", - "error_message": "Bir şeyler ters gitti.\nLütfen çıkış yapın ve tekrar giriş yapın.", + "error_message": "Bir şeyler ters gitti.\nLütfen çıkış yapıp tekrar giriş yapın.", "continue_watching": "İzlemeye Devam Et", "next_up": "Sonraki", - "continue_and_next_up": "Continue & Next Up", - "recently_added_in": "{{libraryName}}'de Yakınlarda Eklendi", + "continue_and_next_up": "İzlemeye Devam Et & Sıradakiler", + "recently_added_in": "{{libraryName}} Kütüphanesine Son Eklenenler", "suggested_movies": "Önerilen Filmler", "suggested_episodes": "Önerilen Bölümler", "intro": { @@ -110,52 +110,52 @@ "settings_title": "Ayarlar", "log_out_button": "Çıkış Yap", "categories": { - "title": "Categories" + "title": "Kategoriler" }, "playback_controls": { - "title": "Playback & Controls" + "title": "Oynatma & Kontroller" }, "audio_subtitles": { - "title": "Audio & Subtitles" + "title": "Ses & Altyazılar" }, "appearance": { - "title": "Appearance", - "merge_next_up_continue_watching": "Merge Continue Watching & Next Up", - "hide_remote_session_button": "Hide Remote Session Button" + "title": "Görünüm", + "merge_next_up_continue_watching": "İzlemeye Devam Et & Sıradakiler'i birleştir", + "hide_remote_session_button": "Uzak Oturum Butonunu Gizle" }, "network": { - "title": "Network", - "local_network": "Local Network", - "auto_switch_enabled": "Auto-switch when at home", - "auto_switch_description": "Automatically switch to local URL when connected to home WiFi", - "local_url": "Local URL", - "local_url_hint": "Enter your local server address (e.g., http://192.168.1.100:8096)", + "title": "Ağ", + "local_network": "Yerel Ağ", + "auto_switch_enabled": "Evdeyken otomatik geçiş yap", + "auto_switch_description": "Ev WiFi'sine bağlanınca otomatik olarak yerek URL adresine geçiş yap", + "local_url": "Yerel URL Adresi", + "local_url_hint": "Yerel sunucu adresinizi girin (http://192.168.1.100:8096, gibi)", "local_url_placeholder": "http://192.168.1.100:8096", - "home_wifi_networks": "Home WiFi Networks", - "add_current_network": "Add \"{{ssid}}\"", - "not_connected_to_wifi": "Not connected to WiFi", - "no_networks_configured": "No networks configured", - "add_network_hint": "Add your home WiFi network to enable auto-switching", - "current_wifi": "Current WiFi", - "using_url": "Using", - "local": "Local URL", - "remote": "Remote URL", - "not_connected": "Not connected", - "current_server": "Current Server", - "remote_url": "Remote URL", - "active_url": "Active URL", - "not_configured": "Not configured", - "network_added": "Network added", - "network_already_added": "Network already added", - "no_wifi_connected": "Not connected to WiFi", - "permission_denied": "Location permission denied", - "permission_denied_explanation": "Location permission is required to detect WiFi network for auto-switching. Please enable it in Settings." + "home_wifi_networks": "Ev WiFi ağları", + "add_current_network": "\"{{ssid}}\"'yi ekle", + "not_connected_to_wifi": "WiFi'a bağlı değil", + "no_networks_configured": "Herhangi bir ağ ayarlanmadı", + "add_network_hint": "Otomatik geçişi etkinleştirmek için ev WiFi'nizi ekleyin", + "current_wifi": "Şu anki WiFi", + "using_url": "Kullanılıyor", + "local": "Yerel URL Adresi", + "remote": "Uzak URL Adresi", + "not_connected": "Bağlı değil", + "current_server": "Geçerli Sunucu", + "remote_url": "Uzak URL Adresi", + "active_url": "Aktif URL Adresi", + "not_configured": "Yapılandırılmamış", + "network_added": "Ağ eklendi", + "network_already_added": "Ağ zaten eklendi", + "no_wifi_connected": "WiFi'a bağlı değil", + "permission_denied": "Konum izni reddedildi", + "permission_denied_explanation": "Otomatik geçiş yapabilmek için WiFi ağını algılayabilmek için konum izni gereklidir. Lütfen Ayarlarda etkinleştirin." }, "user_info": { "user_info_title": "Kullanıcı Bilgisi", "user": "Kullanıcı", "server": "Sunucu", - "token": "Token", + "token": "Erişim Anahtarı", "app_version": "Uygulama Sürümü" }, "quick_connect": { @@ -172,20 +172,20 @@ "media_controls_title": "Medya Kontrolleri", "forward_skip_length": "İleri Sarma Uzunluğu", "rewind_length": "Geri Sarma Uzunluğu", - "seconds_unit": "s" + "seconds_unit": "sn" }, "gesture_controls": { - "gesture_controls_title": "Gesture Controls", - "horizontal_swipe_skip": "Horizontal Swipe to Skip", - "horizontal_swipe_skip_description": "Swipe left/right when controls are hidden to skip", - "left_side_brightness": "Left Side Brightness Control", - "left_side_brightness_description": "Swipe up/down on left side to adjust brightness", - "right_side_volume": "Right Side Volume Control", - "right_side_volume_description": "Swipe up/down on right side to adjust volume", - "hide_volume_slider": "Hide Volume Slider", - "hide_volume_slider_description": "Hide the volume slider in the video player", - "hide_brightness_slider": "Hide Brightness Slider", - "hide_brightness_slider_description": "Hide the brightness slider in the video player" + "gesture_controls_title": "Hareketle Kontrol", + "horizontal_swipe_skip": "Atlamak için yatay kaydırma", + "horizontal_swipe_skip_description": "Kontroller gizliyken sola/sağa kaydırarak atlama", + "left_side_brightness": "Sol Taraf Parlaklık Kontrolü", + "left_side_brightness_description": "Sol tarafta aşağı/yukarı kaydırarak parlaklık ayarı", + "right_side_volume": "Sağ Taraf Ses Kontrolü", + "right_side_volume_description": "Sağ tarafta aşağı/yukarı kaydırarak ses ayarı", + "hide_volume_slider": "Ses Ayarını Gizle", + "hide_volume_slider_description": "Video oynatıcıda ses ayarını gizle", + "hide_brightness_slider": "Parlaklık Ayarını Gizle", + "hide_brightness_slider_description": "Video oynatıcıda parlaklık ayarını gizle" }, "audio": { "audio_title": "Ses", @@ -195,12 +195,12 @@ "none": "Yok", "language": "Dil", "transcode_mode": { - "title": "Audio Transcoding", - "description": "Controls how surround audio (7.1, TrueHD, DTS-HD) is handled", - "auto": "Auto", - "stereo": "Force Stereo", - "5_1": "Allow 5.1", - "passthrough": "Passthrough" + "title": "Ses Kod Dönüştürmesi", + "description": "Surround sesin (7.1, TrueHD, DTS-HD) nasıl işleneceğini kontrol eder.", + "auto": "Oto", + "stereo": "Stereo'ya zorla", + "5_1": "5.1'e izin ver", + "passthrough": "Doğrudan geçiş" } }, "subtitles": { @@ -220,60 +220,60 @@ "None": "Yok", "OnlyForced": "Sadece Zorunlu" }, - "text_color": "Text Color", - "background_color": "Background Color", - "outline_color": "Outline Color", - "outline_thickness": "Outline Thickness", - "background_opacity": "Background Opacity", - "outline_opacity": "Outline Opacity", - "bold_text": "Bold Text", + "text_color": "Metin Rengi", + "background_color": "Arkaplan Rengi", + "outline_color": "Kenarlık Rengi", + "outline_thickness": "Kenarlık kalınlığı", + "background_opacity": "Arkaplan Opaklığı", + "outline_opacity": "Kenarlık Opaklığı", + "bold_text": "Kalın Metin", "colors": { - "Black": "Black", - "Gray": "Gray", - "Silver": "Silver", - "White": "White", - "Maroon": "Maroon", - "Red": "Red", - "Fuchsia": "Fuchsia", - "Yellow": "Yellow", - "Olive": "Olive", - "Green": "Green", - "Teal": "Teal", - "Lime": "Lime", - "Purple": "Purple", - "Navy": "Navy", - "Blue": "Blue", - "Aqua": "Aqua" + "Black": "Siyah", + "Gray": "Gri", + "Silver": "Gümüş", + "White": "Beyaz", + "Maroon": "Kestane", + "Red": "Kırmızı", + "Fuchsia": "Fuşya", + "Yellow": "Sarı", + "Olive": "Zeytin yeşili", + "Green": "Yeşil", + "Teal": "Deniz mavisi", + "Lime": "Limon", + "Purple": "Mor", + "Navy": "Lacivert", + "Blue": "Mavi", + "Aqua": "Açık Mavi" }, "thickness": { "None": "Hiçbiri", - "Thin": "Thin", + "Thin": "İnce", "Normal": "Normal", - "Thick": "Thick" + "Thick": "Kalın" }, - "subtitle_color": "Subtitle Color", - "subtitle_background_color": "Background Color", - "subtitle_font": "Subtitle Font", - "ksplayer_title": "KSPlayer Settings", - "hardware_decode": "Hardware Decoding", - "hardware_decode_description": "Use hardware acceleration for video decoding. Disable if you experience playback issues." + "subtitle_color": "Altyazı Rengi", + "subtitle_background_color": "Arkaplan Rengi", + "subtitle_font": "Altyazı Yazı Tipi", + "ksplayer_title": "KSPlayer Ayarları", + "hardware_decode": "Donanımsal Kod Çözme", + "hardware_decode_description": "Video kod çözme için donanımsal hızlandırma kullan. Oynatma sorunları yaşıyorsanız devre dışı bırakın." }, "vlc_subtitles": { - "title": "VLC Subtitle Settings", - "hint": "Customize subtitle appearance for VLC player. Changes take effect on next playback.", - "text_color": "Text Color", - "background_color": "Background Color", - "background_opacity": "Background Opacity", - "outline_color": "Outline Color", - "outline_opacity": "Outline Opacity", - "outline_thickness": "Outline Thickness", - "bold": "Bold Text", - "margin": "Bottom Margin" + "title": "VLC Altyazı Ayarları", + "hint": "VLC oynatıcı için altyazı görünümünü değiştirin. Değişiklikler bir sonraki oynatmada etkili olacak.", + "text_color": "Metin Rengi", + "background_color": "Arkaplan Rengi", + "background_opacity": "Arkaplan Opaklığı", + "outline_color": "Kenarlık Rengi", + "outline_opacity": "Kenarlık Opaklığı", + "outline_thickness": "Kenarlık Kalınlığı", + "bold": "Kalın Metin", + "margin": "Alt Kenar Boşluğu" }, "video_player": { - "title": "Video Player", - "video_player": "Video Player", - "video_player_description": "Choose which video player to use on iOS.", + "title": "Video oynatıcısı", + "video_player": "Video oynatıcısı", + "video_player_description": "iOS'da hangi video oynatıcının kullanılacağını seçin.", "ksplayer": "KSPlayer", "vlc": "VLC" }, @@ -297,7 +297,7 @@ "video_player": "Video player", "video_players": { "VLC_3": "VLC 3", - "VLC_4": "VLC 4 (Experimental + PiP)" + "VLC_4": "VLC 4 (Deneysel + PiP)" }, "show_custom_menu_links": "Özel Menü Bağlantılarını Göster", "show_large_home_carousel": "Show Large Home Carousel (beta)", @@ -305,24 +305,24 @@ "select_liraries_you_want_to_hide": "Kütüphane sekmesinden ve ana sayfa bölümlerinden gizlemek istediğiniz kütüphaneleri seçin.", "disable_haptic_feedback": "Dokunsal Geri Bildirimi Devre Dışı Bırak", "default_quality": "Varsayılan kalite", - "default_playback_speed": "Default Playback Speed", - "auto_play_next_episode": "Auto-play Next Episode", - "max_auto_play_episode_count": "Max Auto Play Episode Count", + "default_playback_speed": "Varsayılan Oynatma Hızı", + "auto_play_next_episode": "Otomatik Sonraki Bölümü Oynat", + "max_auto_play_episode_count": "En Fazla Otomatik Oynatılacak Bölüm Sayısı", "disabled": "Devre dışı" }, "downloads": { "downloads_title": "İndirmeler" }, "music": { - "title": "Music", - "playback_title": "Playback", - "playback_description": "Configure how music is played.", - "prefer_downloaded": "Prefer Downloaded Songs", - "caching_title": "Caching", - "caching_description": "Automatically cache upcoming tracks for smoother playback.", + "title": "Müzik", + "playback_title": "Oynatma", + "playback_description": "Müziğin nasıl çalınacağını ayarlayın.", + "prefer_downloaded": "İndirilmiş Şarkıları Tercih Et", + "caching_title": "Önbellekleme", + "caching_description": "Akıcı oynatım için gelecek şarkıları otomatik önbelleğe al.", "lookahead_enabled": "Enable Look-Ahead Caching", - "lookahead_count": "Tracks to Pre-cache", - "max_cache_size": "Max Cache Size" + "lookahead_count": "Önden Önbelleklenecek Parça Sayısı", + "max_cache_size": "Maksimum Önbellek Boyutu" }, "plugins": { "plugins_title": "Eklentiler", @@ -345,7 +345,7 @@ "order_by": { "DEFAULT": "Varsayılan", "VOTE_COUNT_AND_AVERAGE": "Vote count and average", - "POPULARITY": "Popularity" + "POPULARITY": "Popülerlik" } }, "marlin_search": { @@ -357,35 +357,35 @@ "save_button": "Kaydet", "toasts": { "saved": "Kaydedildi", - "refreshed": "Settings refreshed from server" + "refreshed": "Ayarlar sunucudan yeniden alındı" }, - "refresh_from_server": "Refresh Settings from Server" + "refresh_from_server": "Ayarları Sunucudan Yeniden Al" }, "streamystats": { - "enable_streamystats": "Enable Streamystats", - "disable_streamystats": "Disable Streamystats", - "enable_search": "Use for Search", - "url": "URL", + "enable_streamystats": "Streamystats'ı Etkinleştir", + "disable_streamystats": "Streamystats'ı Devre Dışı Bırak", + "enable_search": "Arama için kullan", + "url": "URL Adresi", "server_url_placeholder": "http(s)://streamystats.example.com", - "streamystats_search_hint": "Enter the URL for your Streamystats server. The URL should include http or https and optionally the port.", - "read_more_about_streamystats": "Read More About Streamystats.", - "save_button": "Save", - "save": "Save", - "features_title": "Features", + "streamystats_search_hint": "Streamystats sunucu URL'sini girin. URL, http veya https içermeli ve isteğe bağlı olarak portu içerebilir.", + "read_more_about_streamystats": "Streamystats hakkında daha fazla bilgi.", + "save_button": "Kaydet", + "save": "Kaydet", + "features_title": "Özellikler", "home_sections_title": "Home Sections", - "enable_movie_recommendations": "Movie Recommendations", - "enable_series_recommendations": "Series Recommendations", + "enable_movie_recommendations": "Film Önerileri", + "enable_series_recommendations": "Dizi Önerileri", "enable_promoted_watchlists": "Promoted Watchlists", "hide_watchlists_tab": "Hide Watchlists Tab", "home_sections_hint": "Show personalized recommendations and promoted watchlists from Streamystats on the home page.", - "recommended_movies": "Recommended Movies", - "recommended_series": "Recommended Series", + "recommended_movies": "Önerilen Filmler", + "recommended_series": "Önerilen Diziler", "toasts": { - "saved": "Saved", - "refreshed": "Settings refreshed from server", - "disabled": "Streamystats disabled" + "saved": "Kaydedildi", + "refreshed": "Ayarlar sunucudan yeniden alındı", + "disabled": "Streamystats devre dışı" }, - "refresh_from_server": "Refresh Settings from Server" + "refresh_from_server": "Ayarları Sunucudan Yeniden Al" }, "kefinTweaks": { "watchlist_enabler": "Enable our Watchlist integration", @@ -398,18 +398,18 @@ "device_usage": "Cihaz {{availableSpace}}%", "size_used": "{{used}} / {{total}} kullanıldı", "delete_all_downloaded_files": "Tüm indirilen dosyaları sil", - "music_cache_title": "Music Cache", + "music_cache_title": "Müzik Ön Belleği", "music_cache_description": "Automatically cache songs as you listen for smoother playback and offline support", - "enable_music_cache": "Enable Music Cache", - "clear_music_cache": "Clear Music Cache", - "music_cache_size": "{{size}} cached", - "music_cache_cleared": "Music cache cleared", - "delete_all_downloaded_songs": "Delete All Downloaded Songs", - "downloaded_songs_size": "{{size}} downloaded", - "downloaded_songs_deleted": "Downloaded songs deleted" + "enable_music_cache": "Müzik Ön Belleğini Etkinleştir", + "clear_music_cache": "Müzik Ön Belleğini Temizle", + "music_cache_size": "{{size}} ön belleklendi", + "music_cache_cleared": "Müzik ön belleği temizlendi", + "delete_all_downloaded_songs": "Tüm İndirilen Müzikleri Sil", + "downloaded_songs_size": "{{size}} indirildi", + "downloaded_songs_deleted": "İndirilen müzikler silindi" }, "intro": { - "title": "Intro", + "title": "Giriş", "show_intro": "Tanıtımı Göster", "reset_intro": "Tanıtımı Sıfırla" }, @@ -417,7 +417,7 @@ "logs_title": "Günlükler", "export_logs": "Export logs", "click_for_more_info": "Click for more info", - "level": "Level", + "level": "Düzey", "no_logs_available": "Günlükler mevcut değil", "delete_all_logs": "Tüm günlükleri sil" }, @@ -433,22 +433,22 @@ } }, "sessions": { - "title": "Sessions", - "no_active_sessions": "No Active Sessions" + "title": "Oturumlar", + "no_active_sessions": "Aktif Oturum Yok" }, "downloads": { "downloads_title": "İndirilenler", "tvseries": "Diziler", "movies": "Filmler", "queue": "Sıra", - "other_media": "Other media", + "other_media": "Diğer medya", "queue_hint": "Sıra ve indirmeler uygulama yeniden başlatıldığında kaybolacaktır", "no_items_in_queue": "Sırada öğe yok", "no_downloaded_items": "İndirilen öğe yok", "delete_all_movies_button": "Tüm Filmleri Sil", "delete_all_tvseries_button": "Tüm Dizileri Sil", "delete_all_button": "Tümünü Sil", - "delete_all_other_media_button": "Delete other media", + "delete_all_other_media_button": "Diğer medyayı sil", "active_download": "Aktif indirme", "no_active_downloads": "Aktif indirme yok", "active_downloads": "Aktif indirmeler", @@ -465,49 +465,49 @@ "failed_to_delete_all_movies": "Filmler silinemedi", "deleted_all_tvseries_successfully": "Tüm diziler başarıyla silindi!", "failed_to_delete_all_tvseries": "Diziler silinemedi", - "deleted_media_successfully": "Deleted other media Successfully!", + "deleted_media_successfully": "Diğer medya başarıyla silindi!", "failed_to_delete_media": "Failed to Delete other media", - "download_deleted": "Download Deleted", + "download_deleted": "İndirme silindi", "download_cancelled": "İndirme iptal edildi", - "could_not_delete_download": "Could Not Delete Download", - "download_paused": "Download Paused", - "could_not_pause_download": "Could Not Pause Download", - "download_resumed": "Download Resumed", - "could_not_resume_download": "Could Not Resume Download", + "could_not_delete_download": "İndirme Silinemedi", + "download_paused": "İndirme Duraklatıldı", + "could_not_pause_download": "İndirme Duraklatılamadı", + "download_resumed": "İndirme Devam Ediyor", + "could_not_resume_download": "İndirme Devam Ettirilemedi", "download_completed": "İndirme tamamlandı", - "download_failed": "Download Failed", + "download_failed": "İndirme başarısız oldu", "download_failed_for_item": "{{item}} için indirme başarısız oldu - {{error}}", "download_completed_for_item": "{{item}} için indirme tamamlandı", - "download_started_for_item": "Download Started for {{item}}", - "failed_to_start_download": "Failed to start download", - "item_already_downloading": "{{item}} is already downloading", - "all_files_deleted": "All Downloads Deleted Successfully", - "files_deleted_by_type": "{{count}} {{type}} deleted", + "download_started_for_item": "{{item}} için indirme başladı", + "failed_to_start_download": "İndirme başlatılamadı", + "item_already_downloading": "{{item}} zaten indiriliyor", + "all_files_deleted": "Bütün indirilenler başarıyla silindi", + "files_deleted_by_type": "{{count}} {{type}} silindi", "all_files_folders_and_jobs_deleted_successfully": "Tüm dosyalar, klasörler ve işler başarıyla silindi", - "failed_to_clean_cache_directory": "Failed to clean cache directory", - "could_not_get_download_url_for_item": "Could not get download URL for {{itemName}}", + "failed_to_clean_cache_directory": "Önbellek dizini temizlenemedi", + "could_not_get_download_url_for_item": "{{itemName}} için indirme URL'si alınamadı", "go_to_downloads": "İndirmelere git", - "file_deleted": "{{item}} deleted" + "file_deleted": "{{item}} silindi" } } }, "common": { - "select": "Select", - "no_trailer_available": "No trailer available", + "select": "Seç", + "no_trailer_available": "Fragman mevcut değil", "video": "Video", "audio": "Ses", "subtitle": "Altyazı", - "play": "Play", - "none": "None", - "track": "Track", - "cancel": "Cancel", - "delete": "Delete", - "ok": "OK", - "remove": "Remove", - "next": "Next", - "back": "Back", - "continue": "Continue", - "verifying": "Verifying..." + "play": "Oynat", + "none": "Hiçbiri", + "track": "Parça", + "cancel": "Vazgeç", + "delete": "Sil", + "ok": "Tamam", + "remove": "Kaldır", + "next": "Sonraki", + "back": "Geri", + "continue": "Devam", + "verifying": "Doğrulanıyor..." }, "search": { "search": "Ara...", @@ -521,10 +521,10 @@ "episodes": "Bölümler", "collections": "Koleksiyonlar", "actors": "Oyuncular", - "artists": "Artists", - "albums": "Albums", - "songs": "Songs", - "playlists": "Playlists", + "artists": "Sanatçılar", + "albums": "Albümler", + "songs": "Şarkılar", + "playlists": "Çalma listeleri", "request_movies": "Film Talep Et", "request_series": "Dizi Talep Et", "recently_added": "Son Eklenenler", @@ -572,7 +572,7 @@ "genres": "Türler", "years": "Yıllar", "sort_by": "Sırala", - "filter_by": "Filter By", + "filter_by": "Filtrele", "sort_order": "Sıralama düzeni", "tags": "Etiketler" } @@ -604,11 +604,11 @@ "index": "İndeks:", "continue_watching": "İzlemeye devam et", "go_back": "Geri", - "downloaded_file_title": "You have this file downloaded", - "downloaded_file_message": "Do you want to play the downloaded file?", - "downloaded_file_yes": "Yes", - "downloaded_file_no": "No", - "downloaded_file_cancel": "Cancel" + "downloaded_file_title": "Bu dosya indirilmiş", + "downloaded_file_message": "İndirilmiş dosyayı oynatmak ister misiniz?", + "downloaded_file_yes": "Evet", + "downloaded_file_no": "Hayır", + "downloaded_file_cancel": "Vazgeç" }, "item_card": { "next_up": "Sıradaki", @@ -624,7 +624,7 @@ "no_similar_items_found": "Benzer öge bulunamadı", "video": "Video", "more_details": "Daha fazla detay", - "media_options": "Media Options", + "media_options": "Medya Seçenekleri", "quality": "Kalite", "audio": "Ses", "subtitles": "Altyazı", @@ -639,7 +639,7 @@ "download_episode": "Bölümü indir", "download_movie": "Filmi indir", "download_x_item": "{{item_count}} tane ögeyi indir", - "download_unwatched_only": "Unwatched Only", + "download_unwatched_only": "Yalnızca İzlenmemişler", "download_button": "İndir" } }, @@ -693,10 +693,10 @@ "number_episodes": "Bölüm {{episode_number}}", "born": "Doğum", "appearances": "Görünmeler", - "approve": "Approve", - "decline": "Decline", - "requested_by": "Requested by {{user}}", - "unknown_user": "Unknown User", + "approve": "Onayla", + "decline": "Reddet", + "requested_by": "{{user}} tarafından istendi", + "unknown_user": "Bilinmeyen Kullanıcı", "toasts": { "jellyseer_does_not_meet_requirements": "Jellyseerr sunucusu minimum sürüm gereksinimlerini karşılamıyor! Lütfen en az 2.0.0 sürümüne güncelleyin", "jellyseerr_test_failed": "Jellyseerr testi başarısız oldu. Lütfen tekrar deneyin.", @@ -705,10 +705,10 @@ "requested_item": "{{item}} talep edildi!", "you_dont_have_permission_to_request": "İstek göndermeye izniniz yok!", "something_went_wrong_requesting_media": "Medya talep edilirken bir şeyler ters gitti!", - "request_approved": "Request Approved!", - "request_declined": "Request Declined!", - "failed_to_approve_request": "Failed to Approve Request", - "failed_to_decline_request": "Failed to Decline Request" + "request_approved": "İstek Onaylandı!", + "request_declined": "İstek Reddedildi!", + "failed_to_approve_request": "İsteği Onaylama Başarısız Oldu", + "failed_to_decline_request": "İsteği Reddetme Başarısız Oldu" } }, "tabs": { @@ -719,127 +719,127 @@ "favorites": "Favoriler" }, "music": { - "title": "Music", + "title": "Müzik", "tabs": { - "suggestions": "Suggestions", - "albums": "Albums", - "artists": "Artists", - "playlists": "Playlists", - "tracks": "tracks" + "suggestions": "Öneriler", + "albums": "Albümler", + "artists": "Sanatçılar", + "playlists": "Çalma listeleri", + "tracks": "parçalar" }, "filters": { - "all": "All" + "all": "Tümü" }, - "recently_added": "Recently Added", - "recently_played": "Recently Played", - "frequently_played": "Frequently Played", - "explore": "Explore", - "top_tracks": "Top Tracks", - "play": "Play", - "shuffle": "Shuffle", - "play_top_tracks": "Play Top Tracks", - "no_suggestions": "No suggestions available", - "no_albums": "No albums found", - "no_artists": "No artists found", - "no_playlists": "No playlists found", - "album_not_found": "Album not found", - "artist_not_found": "Artist not found", - "playlist_not_found": "Playlist not found", + "recently_added": "Son Eklenenler", + "recently_played": "Son Oynatılanlar", + "frequently_played": "Sık Oynatılanlar", + "explore": "Keşfet", + "top_tracks": "En Popülar Parçalar", + "play": "Oynat", + "shuffle": "Karıştır", + "play_top_tracks": "En Çok Oynatılan Parçaları Oynat", + "no_suggestions": "Öneri mevcut değil", + "no_albums": "Hiç albüm bulunamadı", + "no_artists": "Hiç sanatçı bulunamadı", + "no_playlists": "Hiç çalma listesi bulunamadı", + "album_not_found": "Albüm bulunamadı", + "artist_not_found": "Sanatçı bulunamadı", + "playlist_not_found": "Çalma listesi bulunamadı", "track_options": { - "play_next": "Play Next", - "add_to_queue": "Add to Queue", - "add_to_playlist": "Add to Playlist", - "download": "Download", - "downloaded": "Downloaded", - "downloading": "Downloading...", - "cached": "Cached", - "delete_download": "Delete Download", - "delete_cache": "Remove from Cache", - "go_to_artist": "Go to Artist", - "go_to_album": "Go to Album", - "add_to_favorites": "Add to Favorites", - "remove_from_favorites": "Remove from Favorites", - "remove_from_playlist": "Remove from Playlist" + "play_next": "Sıradakini Çal", + "add_to_queue": "Sıraya Ekle", + "add_to_playlist": "Çalma listesine ekle", + "download": "İndir", + "downloaded": "İndirildi", + "downloading": "İndiriliyor...", + "cached": "Önbellekte", + "delete_download": "İndirmeyi Sil", + "delete_cache": "Ön bellekten kaldır", + "go_to_artist": "Sanatçıya Git", + "go_to_album": "Albüme Git", + "add_to_favorites": "Favorilere Ekle", + "remove_from_favorites": "Favorilerden Kaldır", + "remove_from_playlist": "Çalma Listesinden Kaldır" }, "playlists": { - "create_playlist": "Create Playlist", - "playlist_name": "Playlist Name", - "enter_name": "Enter playlist name", - "create": "Create", - "search_playlists": "Search playlists...", - "added_to": "Added to {{name}}", - "added": "Added to playlist", - "removed_from": "Removed from {{name}}", - "removed": "Removed from playlist", - "created": "Playlist created", - "create_new": "Create New Playlist", - "failed_to_add": "Failed to add to playlist", - "failed_to_remove": "Failed to remove from playlist", - "failed_to_create": "Failed to create playlist", - "delete_playlist": "Delete Playlist", - "delete_confirm": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.", - "deleted": "Playlist deleted", - "failed_to_delete": "Failed to delete playlist" + "create_playlist": "Çalma Listesi Oluştur", + "playlist_name": "Çalma Listesi Adı", + "enter_name": "Çalma listesi adı girin", + "create": "Oluştur", + "search_playlists": "Çalma listelerini ara...", + "added_to": "Şu çalma listesine eklendi: {{name}}", + "added": "Çalma listesine eklendi", + "removed_from": "Şu çalma listesinden kaldırıldı: {{name}}", + "removed": "Çalma listesinden kaldır", + "created": "Çalma listesi oluşturuldu", + "create_new": "Yeni Çalma Listesi Oluştur", + "failed_to_add": "Çalma listesine eklenemedi", + "failed_to_remove": "Çalma listesinden kaldırılamadı", + "failed_to_create": "Çalma listesi oluşturulamadı", + "delete_playlist": "Çalma Listesini Sil", + "delete_confirm": "\"{{name}}\" adlı çalma listesini silmek istediğinize emin misiniz? Bu işlem geri alınamaz.", + "deleted": "Çalma listesi silindi", + "failed_to_delete": "Çalma listesi oluşturulamadı" }, "sort": { - "title": "Sort By", - "alphabetical": "Alphabetical", - "date_created": "Date Created" + "title": "Sırala", + "alphabetical": "Alfabetik", + "date_created": "Oluşturulma Tarihi" } }, "watchlists": { - "title": "Watchlists", - "my_watchlists": "My Watchlists", - "public_watchlists": "Public Watchlists", - "create_title": "Create Watchlist", - "edit_title": "Edit Watchlist", - "create_button": "Create Watchlist", - "save_button": "Save Changes", - "delete_button": "Delete", - "remove_button": "Remove", - "cancel_button": "Cancel", + "title": "İzleme listeleri", + "my_watchlists": "İzleme listelerim", + "public_watchlists": "Herkese açık izleme listeleri", + "create_title": "İzleme listesi oluştur", + "edit_title": "İzleme listesini düzenle", + "create_button": "İzleme listesi oluştur", + "save_button": "Değişiklikleri Kaydet", + "delete_button": "Sil", + "remove_button": "Kaldır", + "cancel_button": "Vazgeç", "name_label": "Name", - "name_placeholder": "Enter watchlist name", - "description_label": "Description", - "description_placeholder": "Enter description (optional)", - "is_public_label": "Public Watchlist", - "is_public_description": "Allow others to view this watchlist", - "allowed_type_label": "Content Type", - "sort_order_label": "Default Sort Order", - "empty_title": "No Watchlists", + "name_placeholder": "İzleme listesi adını girin", + "description_label": "Açıklama", + "description_placeholder": "Açıklama girin (isteğe bağlı)", + "is_public_label": "Herkese açık izleme listesi", + "is_public_description": "Başkalarının da bu izleme listesini görmesine izin ver", + "allowed_type_label": "İçerik Türü", + "sort_order_label": "Varsayılan Sıralama", + "empty_title": "İzleme listesi yok", "empty_description": "Create your first watchlist to start organizing your media", - "empty_watchlist": "This watchlist is empty", - "empty_watchlist_hint": "Add items from your library to this watchlist", - "not_configured_title": "Streamystats Not Configured", - "not_configured_description": "Configure Streamystats in settings to use watchlists", - "go_to_settings": "Go to Settings", - "add_to_watchlist": "Add to Watchlist", - "remove_from_watchlist": "Remove from Watchlist", - "select_watchlist": "Select Watchlist", - "create_new": "Create New Watchlist", - "item": "item", - "items": "items", - "public": "Public", - "private": "Private", - "you": "You", - "by_owner": "By another user", - "not_found": "Watchlist not found", - "delete_confirm_title": "Delete Watchlist", + "empty_watchlist": "Bu izleme listesi boş", + "empty_watchlist_hint": "Kütüphanenizdeki nesneleri bu izleme listesine ekleyin", + "not_configured_title": "Streamystats ayarlanmamış", + "not_configured_description": "İzleme listelerini kullanmak için ayarlardan Streamystats'ı ayarlayın", + "go_to_settings": "Ayarlara git", + "add_to_watchlist": "İzleme Listesine Ekle", + "remove_from_watchlist": "İzleme Listesinden Kaldır", + "select_watchlist": "İzleme Listesi Seç", + "create_new": "Yeni İzleme Listesi Oluştur", + "item": "öğe", + "items": "öğeler", + "public": "Herkese Açık", + "private": "Özel", + "you": "Siz", + "by_owner": "Başka kullanıcı tarafından", + "not_found": "İzleme listesi bulunamadı", + "delete_confirm_title": "İzleme listesini sil", "delete_confirm_message": "Are you sure you want to delete \"{{name}}\"? This action cannot be undone.", - "remove_item_title": "Remove from Watchlist", - "remove_item_message": "Remove \"{{name}}\" from this watchlist?", - "loading": "Loading watchlists...", - "no_compatible_watchlists": "No compatible watchlists", - "create_one_first": "Create a watchlist that accepts this content type" + "remove_item_title": "İzleme Listesinden Kaldır", + "remove_item_message": "{{name}} bu izleme listesinden kaldırılsın mı?", + "loading": "İzleme listeleri yükleniyor...", + "no_compatible_watchlists": "Uyumlu izleme listesi yok", + "create_one_first": "Bu içerik türünü kabul eden bir izleme listesi oluşturun" }, "playback_speed": { - "title": "Playback Speed", - "apply_to": "Apply To", - "speed": "Speed", + "title": "Oynatma Hızı", + "apply_to": "Şuna Uygula", + "speed": "Hız", "scope": { - "media": "This media only", - "show": "This show", - "all": "All media (default)" + "media": "Yalnızca bu medyada", + "show": "Bu dizide", + "all": "Bütün medyalarda (varsayılan)" } } }