Compare commits

...

12 Commits

Author SHA1 Message Date
Uruk
a44fefbccb feat(build): enables tvos builds and artifact reporting
Enables tvOS builds, including unsigned variants, and integrates them into the artifact reporting workflow.

This change re-enables the tvOS build jobs, adds a job for unsigned tvOS builds, and updates the artifact reporting workflow to include these new build targets. The artifact comment now displays download links, file sizes, and build durations for all available builds. Also updates workflow dependencies.
2026-02-17 18:50:27 +01:00
renovate[bot]
8a782fb0c9 chore(deps): Update dependency @react-native-community/cli to v20.1.1 (#1413)
Some checks failed
🛡️ CodeQL Analysis / 🔎 Analyze with CodeQL (actions) (push) Has been cancelled
🛡️ CodeQL Analysis / 🔎 Analyze with CodeQL (javascript-typescript) (push) Has been cancelled
🏗️ Build Apps / 🤖 Build Android APK (Phone) (push) Has been cancelled
🏗️ Build Apps / 🤖 Build Android APK (TV) (push) Has been cancelled
🏗️ Build Apps / 🍎 Build iOS IPA (Phone) (push) Has been cancelled
🏗️ Build Apps / 🍎 Build iOS IPA (Phone - Unsigned) (push) Has been cancelled
🔒 Lockfile Consistency Check / 🔍 Check bun.lock and package.json consistency (push) Has been cancelled
🏷️🔀Merge Conflict Labeler / 🏷️ Labeling Merge Conflicts (push) Has been cancelled
🌐 Translation Sync / sync-translations (push) Has been cancelled
🚦 Security & Quality Gate / 📝 Validate PR Title (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Vulnerable Dependencies (push) Has been cancelled
🚦 Security & Quality Gate / 🚑 Expo Doctor Check (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (check) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (format) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (lint) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (typecheck) (push) Has been cancelled
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-31 17:26:38 +01:00
renovate[bot]
7d0b6c37b8 chore(deps): Update dependency react-i18next to v16.5.4 (#1414)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-31 17:26:01 +01:00
renovate[bot]
5443222e4e chore(deps): Update actions/cache action to v5.0.2 (#1397)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-31 17:25:31 +01:00
renovate[bot]
a77e86be21 chore(deps): Update github/codeql-action action to v4.32.0 (#1410)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-31 17:25:22 +01:00
renovate[bot]
9d82549cd6 chore(deps): Update dependency @tanstack/react-query to v5.90.20 (#1405)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-31 17:25:12 +01:00
renovate[bot]
cb5cb8bff7 chore(deps): Update dependency lodash to v4.17.23 [SECURITY] (#1394)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-31 17:25:02 +01:00
renovate[bot]
0b61fb7d98 chore(deps): Update peter-evans/create-pull-request action to v8.1.0 (#1401)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-31 17:24:53 +01:00
renovate[bot]
f762b9017f chore(deps): Update crowdin/github-action action to v2.14.0 (#1400)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-31 17:24:43 +01:00
renovate[bot]
b063fd6405 chore(deps): Update oven-sh/setup-bun action to v2.1.2 (#1399)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-31 17:24:35 +01:00
renovate[bot]
88ac94ebeb chore(deps): Update actions/checkout action to v6.0.2 (#1398)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-31 17:24:24 +01:00
Fredrik Burmester
358e00d8b7 fix(player): resolve tvOS freeze on player exit by reordering mpv options
Some checks failed
🏗️ Build Apps / 🤖 Build Android APK (Phone) (push) Has been cancelled
🏗️ Build Apps / 🤖 Build Android APK (TV) (push) Has been cancelled
🏗️ Build Apps / 🍎 Build iOS IPA (Phone) (push) Has been cancelled
🏗️ Build Apps / 🍎 Build iOS IPA (Phone - Unsigned) (push) Has been cancelled
🔒 Lockfile Consistency Check / 🔍 Check bun.lock and package.json consistency (push) Has been cancelled
🛡️ CodeQL Analysis / 🔎 Analyze with CodeQL (actions) (push) Has been cancelled
🛡️ CodeQL Analysis / 🔎 Analyze with CodeQL (javascript-typescript) (push) Has been cancelled
🏷️🔀Merge Conflict Labeler / 🏷️ Labeling Merge Conflicts (push) Has been cancelled
🚦 Security & Quality Gate / 📝 Validate PR Title (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Vulnerable Dependencies (push) Has been cancelled
🚦 Security & Quality Gate / 🚑 Expo Doctor Check (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (check) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (format) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (lint) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (typecheck) (push) Has been cancelled
🌐 Translation Sync / sync-translations (push) Has been cancelled
2026-01-19 08:41:52 +01:00
10 changed files with 211 additions and 136 deletions

View File

@@ -220,7 +220,10 @@ jobs:
const jobMappings = { const jobMappings = {
'Android Phone': ['🤖 Build Android APK (Phone)', 'build-android-phone'], 'Android Phone': ['🤖 Build Android APK (Phone)', 'build-android-phone'],
'Android TV': ['🤖 Build Android APK (TV)', 'build-android-tv'], 'Android TV': ['🤖 Build Android APK (TV)', 'build-android-tv'],
'iOS Phone': ['🍎 Build iOS IPA (Phone)', 'build-ios-phone'] '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']
}; };
// Create individual status for each job // Create individual status for each job
@@ -353,10 +356,12 @@ jobs:
// Process each expected build target individually // Process each expected build target individually
const buildTargets = [ const buildTargets = [
{ name: 'Android Phone', platform: '🤖', device: '📱', statusKey: 'Android Phone', artifactPattern: /android.*phone/i }, { name: 'Android Phone', platform: '🤖', device: '📱 Phone', statusKey: 'Android Phone', artifactPattern: /android.*phone/i },
{ name: 'Android TV', platform: '🤖', device: '📺', statusKey: 'Android TV', artifactPattern: /android.*tv/i }, { name: 'Android TV', platform: '🤖', device: '📺 TV', statusKey: 'Android TV', artifactPattern: /android.*tv/i },
{ name: 'iOS Phone', platform: '🍎', device: '📱', statusKey: 'iOS Phone', artifactPattern: /ios.*phone/i }, { name: 'iOS', platform: '🍎', device: '📱 Phone', statusKey: 'iOS Phone', artifactPattern: /ios.*phone.*ipa(?!.*unsigned)/i },
{ name: 'iOS TV', platform: '🍎', device: '📺', statusKey: 'iOS TV', artifactPattern: /ios.*tv/i } { name: 'iOS Unsigned', platform: '🍎', device: '📱 Phone Unsigned', statusKey: 'iOS Phone 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) { for (const target of buildTargets) {
@@ -371,16 +376,26 @@ jobs:
let status = '⏳ Pending'; let status = '⏳ Pending';
let downloadLink = '*Waiting for build...*'; let downloadLink = '*Waiting for build...*';
// Special case for iOS TV - show as disabled if (matchingStatus) {
if (target.name === 'iOS TV') {
status = '💤 Disabled';
downloadLink = '*Disabled for now*';
} else if (matchingStatus) {
if (matchingStatus.conclusion === 'success' && matchingArtifact) { if (matchingStatus.conclusion === 'success' && matchingArtifact) {
status = '✅ Complete'; status = '✅ Complete';
const directLink = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${matchingArtifact.workflow_run.id}/artifacts/${matchingArtifact.id}`; 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'; 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') { } else if (matchingStatus.conclusion === 'failure') {
status = `❌ [Failed](${matchingStatus.url})`; status = `❌ [Failed](${matchingStatus.url})`;
downloadLink = '*Build failed*'; downloadLink = '*Build failed*';
@@ -408,7 +423,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`; commentBody += `\n`;

View File

@@ -33,7 +33,7 @@ jobs:
swap-storage: false swap-storage: false
- name: 📥 Checkout code - name: 📥 Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
ref: ${{ github.event.pull_request.head.sha || github.sha }} ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0 fetch-depth: 0
@@ -41,12 +41,12 @@ jobs:
show-progress: false show-progress: false
- name: 🍞 Setup Bun - name: 🍞 Setup Bun
uses: oven-sh/setup-bun@b7a1c7ccf290d58743029c4f6903da283811b979 # v2.1.0 uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
with: with:
bun-version: latest bun-version: latest
- name: 💾 Cache Bun dependencies - name: 💾 Cache Bun dependencies
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: ~/.bun/install/cache path: ~/.bun/install/cache
key: ${{ runner.os }}-${{ runner.arch }}-bun-develop-${{ hashFiles('bun.lock') }} key: ${{ runner.os }}-${{ runner.arch }}-bun-develop-${{ hashFiles('bun.lock') }}
@@ -60,7 +60,7 @@ jobs:
bun run submodule-reload bun run submodule-reload
- name: 💾 Cache Gradle global - name: 💾 Cache Gradle global
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: | path: |
~/.gradle/caches ~/.gradle/caches
@@ -73,7 +73,7 @@ jobs:
run: bun run prebuild run: bun run prebuild
- name: 💾 Cache project Gradle (.gradle) - name: 💾 Cache project Gradle (.gradle)
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: android/.gradle path: android/.gradle
key: ${{ runner.os }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }} key: ${{ runner.os }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }}
@@ -116,7 +116,7 @@ jobs:
swap-storage: false swap-storage: false
- name: 📥 Checkout code - name: 📥 Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
ref: ${{ github.event.pull_request.head.sha || github.sha }} ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0 fetch-depth: 0
@@ -124,12 +124,12 @@ jobs:
show-progress: false show-progress: false
- name: 🍞 Setup Bun - name: 🍞 Setup Bun
uses: oven-sh/setup-bun@b7a1c7ccf290d58743029c4f6903da283811b979 # v2.1.0 uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
with: with:
bun-version: latest bun-version: latest
- name: 💾 Cache Bun dependencies - name: 💾 Cache Bun dependencies
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: ~/.bun/install/cache path: ~/.bun/install/cache
key: ${{ runner.os }}-${{ runner.arch }}-bun-develop-${{ hashFiles('bun.lock') }} key: ${{ runner.os }}-${{ runner.arch }}-bun-develop-${{ hashFiles('bun.lock') }}
@@ -143,7 +143,7 @@ jobs:
bun run submodule-reload bun run submodule-reload
- name: 💾 Cache Gradle global - name: 💾 Cache Gradle global
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: | path: |
~/.gradle/caches ~/.gradle/caches
@@ -156,7 +156,7 @@ jobs:
run: bun run prebuild:tv run: bun run prebuild:tv
- name: 💾 Cache project Gradle (.gradle) - name: 💾 Cache project Gradle (.gradle)
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: android/.gradle path: android/.gradle
key: ${{ runner.os }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }} key: ${{ runner.os }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }}
@@ -187,7 +187,7 @@ jobs:
steps: steps:
- name: 📥 Checkout code - name: 📥 Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
ref: ${{ github.event.pull_request.head.sha || github.sha }} ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0 fetch-depth: 0
@@ -195,12 +195,12 @@ jobs:
show-progress: false show-progress: false
- name: 🍞 Setup Bun - name: 🍞 Setup Bun
uses: oven-sh/setup-bun@b7a1c7ccf290d58743029c4f6903da283811b979 # v2.1.0 uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
with: with:
bun-version: latest bun-version: latest
- name: 💾 Cache Bun dependencies - name: 💾 Cache Bun dependencies
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: ~/.bun/install/cache path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }} key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }}
@@ -251,7 +251,7 @@ jobs:
steps: steps:
- name: 📥 Checkout code - name: 📥 Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
ref: ${{ github.event.pull_request.head.sha || github.sha }} ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0 fetch-depth: 0
@@ -259,12 +259,12 @@ jobs:
show-progress: false show-progress: false
- name: 🍞 Setup Bun - name: 🍞 Setup Bun
uses: oven-sh/setup-bun@b7a1c7ccf290d58743029c4f6903da283811b979 # v2.1.0 uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
with: with:
bun-version: latest bun-version: latest
- name: 💾 Cache Bun dependencies - name: 💾 Cache Bun dependencies
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: ~/.bun/install/cache path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }} key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }}
@@ -299,67 +299,123 @@ jobs:
path: build/*.ipa path: build/*.ipa
retention-days: 7 retention-days: 7
# Disabled for now - uncomment when ready to build iOS TV 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'))
# 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
# runs-on: macos-26 name: 🍎 Build tvOS IPA
# name: 🍎 Build iOS IPA (TV) permissions:
# permissions: contents: read
# contents: read
# steps:
# steps: - name: 📥 Checkout code
# - name: 📥 Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with:
# with: ref: ${{ github.event.pull_request.head.sha || github.sha }}
# ref: ${{ github.event.pull_request.head.sha || github.sha }} fetch-depth: 0
# fetch-depth: 0 submodules: recursive
# submodules: recursive show-progress: false
# show-progress: false
# - name: 🍞 Setup Bun
# - name: 🍞 Setup Bun uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
# uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2.0.2 with:
# with: bun-version: latest
# bun-version: latest
# - name: 💾 Cache Bun dependencies
# - name: 💾 Cache Bun dependencies uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
# uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with:
# with: path: ~/.bun/install/cache
# path: ~/.bun/install/cache key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }}
# key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }} restore-keys: |
# restore-keys: | ${{ runner.os }}-bun-cache
# ${{ runner.os }}-bun-cache
# - name: 📦 Install dependencies and reload submodules
# - name: 📦 Install dependencies and reload submodules run: |
# run: | bun install --frozen-lockfile
# bun install --frozen-lockfile bun run submodule-reload
# bun run submodule-reload
# - name: 🛠️ Generate project files
# - name: 🛠️ Generate project files run: bun run prebuild:tv
# run: bun run prebuild:tv
# - name: 🔧 Setup Xcode
# - name: 🔧 Setup Xcode uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1
# uses: maxim-lobanov/setup-xcode@v1 with:
# with: xcode-version: "26.2"
# xcode-version: '26.0.1'
# - name: 🏗️ Setup EAS
# - name: 🏗️ Setup EAS uses: expo/expo-github-action@main
# uses: expo/expo-github-action@main with:
# with: eas-version: latest
# eas-version: latest token: ${{ secrets.EXPO_TOKEN }}
# token: ${{ secrets.EXPO_TOKEN }} eas-cache: true
# eas-cache: true
# - name: 🚀 Build iOS app
# - name: 🚀 Build iOS app env:
# env: EXPO_TV: 1
# EXPO_TV: 1 run: eas build -p ios --local --non-interactive
# run: eas build -p ios --local --non-interactive
# - name: 📅 Set date tag
# - name: 📅 Set date tag run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV
# run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV
# - name: 📤 Upload IPA artifact
# - name: 📤 Upload IPA artifact uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
# uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with:
# with: name: streamyfin-ios-tv-ipa-${{ env.DATE_TAG }}
# name: streamyfin-ios-tv-ipa-${{ env.DATE_TAG }} path: build-*.ipa
# path: build-*.ipa retention-days: 7
# retention-days: 7
build-ios-tv-unsigned:
if: (!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
with:
xcode-version: "26.2"
- name: 🚀 Build iOS app
env:
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
- name: 📤 Upload IPA artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: streamyfin-ios-tv-unsigned-ipa-${{ env.DATE_TAG }}
path: build/*.ipa
retention-days: 7

View File

@@ -19,7 +19,7 @@ jobs:
steps: steps:
- name: 📥 Checkout repository - name: 📥 Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
ref: ${{ github.event.pull_request.head.sha || github.sha }} ref: ${{ github.event.pull_request.head.sha || github.sha }}
show-progress: false show-progress: false
@@ -27,12 +27,12 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- name: 🍞 Setup Bun - name: 🍞 Setup Bun
uses: oven-sh/setup-bun@b7a1c7ccf290d58743029c4f6903da283811b979 # v2.1.0 uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
with: with:
bun-version: latest bun-version: latest
- name: 💾 Cache Bun dependencies - name: 💾 Cache Bun dependencies
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: | path: |
~/.bun/install/cache ~/.bun/install/cache

View File

@@ -24,16 +24,16 @@ jobs:
steps: steps:
- name: 📥 Checkout repository - name: 📥 Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: 🏁 Initialize CodeQL - name: 🏁 Initialize CodeQL
uses: github/codeql-action/init@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 uses: github/codeql-action/init@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality queries: +security-extended,security-and-quality
- name: 🛠️ Autobuild - name: 🛠️ Autobuild
uses: github/codeql-action/autobuild@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 uses: github/codeql-action/autobuild@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0
- name: 🧪 Perform CodeQL Analysis - name: 🧪 Perform CodeQL Analysis
uses: github/codeql-action/analyze@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 uses: github/codeql-action/analyze@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4.32.0

View File

@@ -23,12 +23,12 @@ jobs:
steps: steps:
- name: 📥 Checkout Repository - name: 📥 Checkout Repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
fetch-depth: 0 fetch-depth: 0
- name: 🌐 Sync Translations with Crowdin - name: 🌐 Sync Translations with Crowdin
uses: crowdin/github-action@60debf382ee245b21794321190ad0501db89d8c1 # v2.13.0 uses: crowdin/github-action@b4b468cffefb50bdd99dd83e5d2eaeb63c880380 # v2.14.0
with: with:
upload_sources: true upload_sources: true
upload_translations: true upload_translations: true

View File

@@ -51,7 +51,7 @@ jobs:
contents: read contents: read
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
ref: ${{ github.event.pull_request.head.sha || github.sha }} ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0 fetch-depth: 0
@@ -69,14 +69,14 @@ jobs:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- name: 🛒 Checkout repository - name: 🛒 Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
ref: ${{ github.event.pull_request.head.sha || github.sha }} ref: ${{ github.event.pull_request.head.sha || github.sha }}
submodules: recursive submodules: recursive
fetch-depth: 0 fetch-depth: 0
- name: 🍞 Setup Bun - name: 🍞 Setup Bun
uses: oven-sh/setup-bun@b7a1c7ccf290d58743029c4f6903da283811b979 # v2.1.0 uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
with: with:
bun-version: latest bun-version: latest
@@ -100,7 +100,7 @@ jobs:
steps: steps:
- name: "📥 Checkout PR code" - name: "📥 Checkout PR code"
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
ref: ${{ github.event.pull_request.head.sha || github.sha }} ref: ${{ github.event.pull_request.head.sha || github.sha }}
submodules: recursive submodules: recursive
@@ -112,7 +112,7 @@ jobs:
node-version: '24.x' node-version: '24.x'
- name: "🍞 Setup Bun" - name: "🍞 Setup Bun"
uses: oven-sh/setup-bun@b7a1c7ccf290d58743029c4f6903da283811b979 # v2.1.0 uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
with: with:
bun-version: latest bun-version: latest

View File

@@ -18,7 +18,7 @@ jobs:
steps: steps:
- name: 📥 Checkout repository - name: 📥 Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: "🟢 Setup Node.js" - name: "🟢 Setup Node.js"
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
@@ -54,7 +54,7 @@ jobs:
dry_run: no-push dry_run: no-push
- name: 📬 Commit and create pull request - name: 📬 Commit and create pull request
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
with: with:
add-paths: .github/ISSUE_TEMPLATE/bug_report.yml add-paths: .github/ISSUE_TEMPLATE/bug_report.yml
branch: ci-update-bug-report branch: ci-update-bug-report

View File

@@ -19,7 +19,7 @@
"@shopify/flash-list": "2.0.2", "@shopify/flash-list": "2.0.2",
"@tanstack/query-sync-storage-persister": "^5.90.18", "@tanstack/query-sync-storage-persister": "^5.90.18",
"@tanstack/react-pacer": "^0.19.1", "@tanstack/react-pacer": "^0.19.1",
"@tanstack/react-query": "5.90.17", "@tanstack/react-query": "5.90.20",
"@tanstack/react-query-persist-client": "^5.90.18", "@tanstack/react-query-persist-client": "^5.90.18",
"axios": "^1.7.9", "axios": "^1.7.9",
"expo": "~54.0.31", "expo": "~54.0.31",
@@ -52,12 +52,12 @@
"expo-web-browser": "~15.0.10", "expo-web-browser": "~15.0.10",
"i18next": "^25.0.0", "i18next": "^25.0.0",
"jotai": "2.16.2", "jotai": "2.16.2",
"lodash": "4.17.21", "lodash": "4.17.23",
"nativewind": "^2.0.11", "nativewind": "^2.0.11",
"patch-package": "^8.0.0", "patch-package": "^8.0.0",
"react": "19.1.0", "react": "19.1.0",
"react-dom": "19.1.0", "react-dom": "19.1.0",
"react-i18next": "16.5.3", "react-i18next": "16.5.4",
"react-native": "0.81.5", "react-native": "0.81.5",
"react-native-awesome-slider": "^2.9.0", "react-native-awesome-slider": "^2.9.0",
"react-native-bottom-tabs": "1.1.0", "react-native-bottom-tabs": "1.1.0",
@@ -97,7 +97,7 @@
"devDependencies": { "devDependencies": {
"@babel/core": "7.28.6", "@babel/core": "7.28.6",
"@biomejs/biome": "2.3.11", "@biomejs/biome": "2.3.11",
"@react-native-community/cli": "20.1.0", "@react-native-community/cli": "20.1.1",
"@react-native-tvos/config-tv": "0.1.4", "@react-native-tvos/config-tv": "0.1.4",
"@types/jest": "29.5.14", "@types/jest": "29.5.14",
"@types/lodash": "4.17.23", "@types/lodash": "4.17.23",
@@ -512,29 +512,29 @@
"@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=="], "@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.0", "", { "dependencies": { "@react-native-community/cli-clean": "20.1.0", "@react-native-community/cli-config": "20.1.0", "@react-native-community/cli-doctor": "20.1.0", "@react-native-community/cli-server-api": "20.1.0", "@react-native-community/cli-tools": "20.1.0", "@react-native-community/cli-types": "20.1.0", "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-441WsVtRe4nGJ9OzA+QMU1+22lA6Q2hRWqqIMKD0wjEMLqcSfOZyu2UL9a/yRpL/dRpyUsU4n7AxqKfTKO/Csg=="], "@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-clean": ["@react-native-community/cli-clean@20.1.0", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.0", "execa": "^5.0.0", "fast-glob": "^3.3.2", "picocolors": "^1.1.1" } }, "sha512-77L4DifWfxAT8ByHnkypge7GBMYpbJAjBGV+toowt5FQSGaTBDcBHCX+FFqFRukD5fH6i8sZ41Gtw+nbfCTTIA=="], "@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-config": ["@react-native-community/cli-config@20.1.0", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.0", "cosmiconfig": "^9.0.0", "deepmerge": "^4.3.0", "fast-glob": "^3.3.2", "joi": "^17.2.1", "picocolors": "^1.1.1" } }, "sha512-1x9rhLLR/dKKb92Lb5O0l0EmUG08FHf+ZVyVEf9M+tX+p5QIm52MRiy43R0UAZ2jJnFApxRk+N3sxoYK4Dtnag=="], "@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-android": ["@react-native-community/cli-config-android@20.1.0", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.0", "fast-glob": "^3.3.2", "fast-xml-parser": "^4.4.1", "picocolors": "^1.1.1" } }, "sha512-3A01ZDyFeCALzzPcwP/fleHoP3sGNq1UX7FzxkTrOFX8RRL9ntXNXQd27E56VU4BBxGAjAJT4Utw8pcOjJceIA=="], "@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-apple": ["@react-native-community/cli-config-apple@20.1.0", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.0", "execa": "^5.0.0", "fast-glob": "^3.3.2", "picocolors": "^1.1.1" } }, "sha512-n6JVs8Q3yxRbtZQOy05ofeb1kGtspGN3SgwPmuaqvURF9fsuS7c4/9up2Kp9C+1D2J1remPJXiZLNGOcJvfpOA=="], "@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-doctor": ["@react-native-community/cli-doctor@20.1.0", "", { "dependencies": { "@react-native-community/cli-config": "20.1.0", "@react-native-community/cli-platform-android": "20.1.0", "@react-native-community/cli-platform-apple": "20.1.0", "@react-native-community/cli-platform-ios": "20.1.0", "@react-native-community/cli-tools": "20.1.0", "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-QfJF1GVjA4PBrIT3SJ0vFFIu0km1vwOmLDlOYVqfojajZJ+Dnvl0f94GN1il/jT7fITAxom///XH3/URvi7YTQ=="], "@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-platform-android": ["@react-native-community/cli-platform-android@20.1.0", "", { "dependencies": { "@react-native-community/cli-config-android": "20.1.0", "@react-native-community/cli-tools": "20.1.0", "execa": "^5.0.0", "logkitty": "^0.7.1", "picocolors": "^1.1.1" } }, "sha512-TeHPDThOwDppQRpndm9kCdRCBI8AMy3HSIQ+iy7VYQXL5BtZ5LfmGdusoj7nVN/ZGn0Lc6Gwts5qowyupXdeKg=="], "@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-apple": ["@react-native-community/cli-platform-apple@20.1.0", "", { "dependencies": { "@react-native-community/cli-config-apple": "20.1.0", "@react-native-community/cli-tools": "20.1.0", "execa": "^5.0.0", "fast-xml-parser": "^4.4.1", "picocolors": "^1.1.1" } }, "sha512-0ih1hrYezSM2cuOlVnwBEFtMwtd8YgpTLmZauDJCv50rIumtkI1cQoOgLoS4tbPCj9U/Vn2a9BFH0DLFOOIacg=="], "@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-ios": ["@react-native-community/cli-platform-ios@20.1.0", "", { "dependencies": { "@react-native-community/cli-platform-apple": "20.1.0" } }, "sha512-XN7Da9z4WsJxtqVtEzY8q2bv22OsvzaFP5zy5+phMWNoJlU4lf7IvBSxqGYMpQ9XhYP7arDw5vmW4W34s06rnA=="], "@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-server-api": ["@react-native-community/cli-server-api@20.1.0", "", { "dependencies": { "@react-native-community/cli-tools": "20.1.0", "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", "ws": "^6.2.3" } }, "sha512-Tb415Oh8syXNT2zOzLzFkBXznzGaqKCiaichxKzGCDKg6JGHp3jSuCmcTcaPeYC7oc32n/S3Psw7798r4Q/7lA=="], "@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-tools": ["@react-native-community/cli-tools@20.1.0", "", { "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-/YmzHGOkY6Bgrv4OaA1L8rFqsBlQd1EB2/ipAoKPiieV0EcB5PUamUSuNeFU3sBZZTYQCUENwX4wgOHgFUlDnQ=="], "@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-types": ["@react-native-community/cli-types@20.1.0", "", { "dependencies": { "joi": "^17.2.1" } }, "sha512-D0kDspcwgbVXyNjwicT7Bb1JgXjijTw1JJd+qxyF/a9+sHv7TU4IchV+gN38QegeXqVyM4Ym7YZIvXMFBmyJqA=="], "@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/netinfo": ["@react-native-community/netinfo@11.4.1", "", { "peerDependencies": { "react-native": ">=0.59" } }, "sha512-B0BYAkghz3Q2V09BF88RA601XursIEA111tnc2JOaN7axJWmNefmfjZqw/KdSxKZp7CZUuPpjBmz/WCR9uaHYg=="], "@react-native-community/netinfo": ["@react-native-community/netinfo@11.4.1", "", { "peerDependencies": { "react-native": ">=0.59" } }, "sha512-B0BYAkghz3Q2V09BF88RA601XursIEA111tnc2JOaN7axJWmNefmfjZqw/KdSxKZp7CZUuPpjBmz/WCR9uaHYg=="],
@@ -602,7 +602,7 @@
"@tanstack/react-pacer": ["@tanstack/react-pacer@0.19.1", "", { "dependencies": { "@tanstack/pacer": "0.17.1", "@tanstack/react-store": "^0.8.0" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-wfGwKLo2gosKr5tsXico+jWJ8LsWsBC8MA1HVtUY/D6dhFduEVizKxRUcvP60I3dRvnoXDbN202g4feJHlivnA=="], "@tanstack/react-pacer": ["@tanstack/react-pacer@0.19.1", "", { "dependencies": { "@tanstack/pacer": "0.17.1", "@tanstack/react-store": "^0.8.0" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-wfGwKLo2gosKr5tsXico+jWJ8LsWsBC8MA1HVtUY/D6dhFduEVizKxRUcvP60I3dRvnoXDbN202g4feJHlivnA=="],
"@tanstack/react-query": ["@tanstack/react-query@5.90.17", "", { "dependencies": { "@tanstack/query-core": "5.90.17" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-PGc2u9KLwohDUSchjW9MZqeDQJfJDON7y4W7REdNBgiFKxQy+Pf7eGjiFWEj5xPqKzAeHYdAb62IWI1a9UJyGQ=="], "@tanstack/react-query": ["@tanstack/react-query@5.90.20", "", { "dependencies": { "@tanstack/query-core": "5.90.20" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-vXBxa+qeyveVO7OA0jX1z+DeyCA4JKnThKv411jd5SORpBKgkcVnYKCiBgECvADvniBX7tobwBmg01qq9JmMJw=="],
"@tanstack/react-query-persist-client": ["@tanstack/react-query-persist-client@5.90.18", "", { "dependencies": { "@tanstack/query-persist-client-core": "5.91.15" }, "peerDependencies": { "@tanstack/react-query": "^5.90.16", "react": "^18 || ^19" } }, "sha512-ToVRTVpjzTrd9S/p7JIvGdLs+Xtz9aDMM/7+TQGSV9notY8Jt64irfAAAkZ05syftLKS+3KPgyKAnHcVeKVbWQ=="], "@tanstack/react-query-persist-client": ["@tanstack/react-query-persist-client@5.90.18", "", { "dependencies": { "@tanstack/query-persist-client-core": "5.91.15" }, "peerDependencies": { "@tanstack/react-query": "^5.90.16", "react": "^18 || ^19" } }, "sha512-ToVRTVpjzTrd9S/p7JIvGdLs+Xtz9aDMM/7+TQGSV9notY8Jt64irfAAAkZ05syftLKS+3KPgyKAnHcVeKVbWQ=="],
@@ -1376,7 +1376,7 @@
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], "lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="],
"lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="], "lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="],
@@ -1640,7 +1640,7 @@
"react-freeze": ["react-freeze@1.0.4", "", { "peerDependencies": { "react": ">=17.0.0" } }, "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA=="], "react-freeze": ["react-freeze@1.0.4", "", { "peerDependencies": { "react": ">=17.0.0" } }, "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA=="],
"react-i18next": ["react-i18next@16.5.3", "", { "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-fo+/NNch37zqxOzlBYrWMx0uy/yInPkRfjSuy4lqKdaecR17nvCHnEUt3QyzA8XjQ2B/0iW/5BhaHR3ZmukpGw=="], "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-is": ["react-is@19.2.3", "", {}, "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA=="], "react-is": ["react-is@19.2.3", "", {}, "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA=="],
@@ -1854,6 +1854,8 @@
"strict-uri-encode": ["strict-uri-encode@2.0.0", "", {}, "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ=="], "strict-uri-encode": ["strict-uri-encode@2.0.0", "", {}, "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ=="],
"strict-url-sanitise": ["strict-url-sanitise@0.0.1", "", {}, "sha512-nuFtF539K8jZg3FjaWH/L8eocCR6gegz5RDOsaWxfdbF5Jqr2VXWxZayjTwUzsWJDC91k2EbnJXp6FuWW+Z4hg=="],
"string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="], "string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="],
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
@@ -2242,7 +2244,7 @@
"@react-navigation/native-stack/color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="], "@react-navigation/native-stack/color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
"@tanstack/react-query/@tanstack/query-core": ["@tanstack/query-core@5.90.17", "", {}, "sha512-hDww+RyyYhjhUfoYQ4es6pbgxY7LNiPWxt4l1nJqhByjndxJ7HIjDxTBtfvMr5HwjYavMrd+ids5g4Rfev3lVQ=="], "@tanstack/react-query/@tanstack/query-core": ["@tanstack/query-core@5.90.20", "", {}, "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg=="],
"@types/babel__core/@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], "@types/babel__core/@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="],

View File

@@ -167,16 +167,17 @@ final class MPVLayerRenderer {
// Use AVFoundation video output - required for PiP support // Use AVFoundation video output - required for PiP support
checkError(mpv_set_option_string(handle, "vo", "avfoundation")) checkError(mpv_set_option_string(handle, "vo", "avfoundation"))
// 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
checkError(mpv_set_option_string(handle, "avfoundation-composite-osd", "yes"))
// Hardware decoding with VideoToolbox // Hardware decoding with VideoToolbox
// On simulator, use software decoding since VideoToolbox is not available // On simulator, use software decoding since VideoToolbox is not available
// On device, use VideoToolbox with software fallback enabled // On device, use VideoToolbox with software fallback enabled
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
checkError(mpv_set_option_string(handle, "hwdec", "no")) checkError(mpv_set_option_string(handle, "hwdec", "no"))
#else #else
// Only enable composite OSD mode on real device (OSD is not supported in simulator).
// This renders subtitles directly onto video frames using the GPU, which is better for PiP since subtitles are baked into the video.
checkError(mpv_set_option_string(handle, "avfoundation-composite-osd", "yes"))
checkError(mpv_set_option_string(handle, "hwdec", "videotoolbox")) checkError(mpv_set_option_string(handle, "hwdec", "videotoolbox"))
#endif #endif
checkError(mpv_set_option_string(handle, "hwdec-codecs", "all")) checkError(mpv_set_option_string(handle, "hwdec-codecs", "all"))

View File

@@ -15,6 +15,7 @@
"android:tv": "cross-env EXPO_TV=1 expo run:android", "android:tv": "cross-env EXPO_TV=1 expo run:android",
"build:android:local": "cd android && cross-env NODE_ENV=production ./gradlew assembleRelease", "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": "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", "prepare": "husky",
"typecheck": "node scripts/typecheck.js", "typecheck": "node scripts/typecheck.js",
"check": "biome check . --max-diagnostics 1000", "check": "biome check . --max-diagnostics 1000",
@@ -39,7 +40,7 @@
"@shopify/flash-list": "2.0.2", "@shopify/flash-list": "2.0.2",
"@tanstack/query-sync-storage-persister": "^5.90.18", "@tanstack/query-sync-storage-persister": "^5.90.18",
"@tanstack/react-pacer": "^0.19.1", "@tanstack/react-pacer": "^0.19.1",
"@tanstack/react-query": "5.90.17", "@tanstack/react-query": "5.90.20",
"@tanstack/react-query-persist-client": "^5.90.18", "@tanstack/react-query-persist-client": "^5.90.18",
"axios": "^1.7.9", "axios": "^1.7.9",
"expo": "~54.0.31", "expo": "~54.0.31",
@@ -72,12 +73,12 @@
"expo-web-browser": "~15.0.10", "expo-web-browser": "~15.0.10",
"i18next": "^25.0.0", "i18next": "^25.0.0",
"jotai": "2.16.2", "jotai": "2.16.2",
"lodash": "4.17.21", "lodash": "4.17.23",
"nativewind": "^2.0.11", "nativewind": "^2.0.11",
"patch-package": "^8.0.0", "patch-package": "^8.0.0",
"react": "19.1.0", "react": "19.1.0",
"react-dom": "19.1.0", "react-dom": "19.1.0",
"react-i18next": "16.5.3", "react-i18next": "16.5.4",
"react-native": "0.81.5", "react-native": "0.81.5",
"react-native-awesome-slider": "^2.9.0", "react-native-awesome-slider": "^2.9.0",
"react-native-bottom-tabs": "1.1.0", "react-native-bottom-tabs": "1.1.0",
@@ -117,7 +118,7 @@
"devDependencies": { "devDependencies": {
"@babel/core": "7.28.6", "@babel/core": "7.28.6",
"@biomejs/biome": "2.3.11", "@biomejs/biome": "2.3.11",
"@react-native-community/cli": "20.1.0", "@react-native-community/cli": "20.1.1",
"@react-native-tvos/config-tv": "0.1.4", "@react-native-tvos/config-tv": "0.1.4",
"@types/jest": "29.5.14", "@types/jest": "29.5.14",
"@types/lodash": "4.17.23", "@types/lodash": "4.17.23",