mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-07-07 04:53:01 +01:00
Compare commits
1 Commits
fix/tv-aud
...
renovate/c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
432b3f63c6 |
24
.github/workflows/build-apps.yml
vendored
24
.github/workflows/build-apps.yml
vendored
@@ -57,7 +57,7 @@ jobs:
|
|||||||
bun-version: "1.3.14"
|
bun-version: "1.3.14"
|
||||||
|
|
||||||
- name: 💾 Cache Bun dependencies
|
- name: 💾 Cache Bun dependencies
|
||||||
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||||
with:
|
with:
|
||||||
path: ~/.bun/install/cache
|
path: ~/.bun/install/cache
|
||||||
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
|
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
|
||||||
@@ -73,13 +73,13 @@ jobs:
|
|||||||
# ubuntu-26.04 defaults to JDK 25, which breaks the RN/AGP native build
|
# ubuntu-26.04 defaults to JDK 25, which breaks the RN/AGP native build
|
||||||
# (Kotlin falls back to JVM_23, the foojay toolchain + CMake configure
|
# (Kotlin falls back to JVM_23, the foojay toolchain + CMake configure
|
||||||
# fail). Pin Temurin 17 for a deterministic Android build.
|
# fail). Pin Temurin 17 for a deterministic Android build.
|
||||||
uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: temurin
|
||||||
java-version: "17"
|
java-version: "17"
|
||||||
|
|
||||||
- name: 💾 Cache Gradle global
|
- name: 💾 Cache Gradle global
|
||||||
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches/modules-2
|
~/.gradle/caches/modules-2
|
||||||
@@ -92,7 +92,7 @@ jobs:
|
|||||||
run: bun run prebuild
|
run: bun run prebuild
|
||||||
|
|
||||||
- name: 💾 Cache project Gradle (.gradle)
|
- name: 💾 Cache project Gradle (.gradle)
|
||||||
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||||
with:
|
with:
|
||||||
path: android/.gradle
|
path: android/.gradle
|
||||||
key: ${{ runner.os }}-${{ runner.arch }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }}
|
key: ${{ runner.os }}-${{ runner.arch }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }}
|
||||||
@@ -157,7 +157,7 @@ jobs:
|
|||||||
bun-version: "1.3.14"
|
bun-version: "1.3.14"
|
||||||
|
|
||||||
- name: 💾 Cache Bun dependencies
|
- name: 💾 Cache Bun dependencies
|
||||||
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||||
with:
|
with:
|
||||||
path: ~/.bun/install/cache
|
path: ~/.bun/install/cache
|
||||||
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
|
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
|
||||||
@@ -173,13 +173,13 @@ jobs:
|
|||||||
# ubuntu-26.04 defaults to JDK 25, which breaks the RN/AGP native build
|
# ubuntu-26.04 defaults to JDK 25, which breaks the RN/AGP native build
|
||||||
# (Kotlin falls back to JVM_23, the foojay toolchain + CMake configure
|
# (Kotlin falls back to JVM_23, the foojay toolchain + CMake configure
|
||||||
# fail). Pin Temurin 17 for a deterministic Android build.
|
# fail). Pin Temurin 17 for a deterministic Android build.
|
||||||
uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0
|
uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: temurin
|
||||||
java-version: "17"
|
java-version: "17"
|
||||||
|
|
||||||
- name: 💾 Cache Gradle global
|
- name: 💾 Cache Gradle global
|
||||||
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.gradle/caches/modules-2
|
~/.gradle/caches/modules-2
|
||||||
@@ -192,7 +192,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@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||||
with:
|
with:
|
||||||
path: android/.gradle
|
path: android/.gradle
|
||||||
key: ${{ runner.os }}-${{ runner.arch }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }}
|
key: ${{ runner.os }}-${{ runner.arch }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }}
|
||||||
@@ -244,7 +244,7 @@ jobs:
|
|||||||
bun-version: "1.3.14"
|
bun-version: "1.3.14"
|
||||||
|
|
||||||
- name: 💾 Cache Bun dependencies
|
- name: 💾 Cache Bun dependencies
|
||||||
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||||
with:
|
with:
|
||||||
path: ~/.bun/install/cache
|
path: ~/.bun/install/cache
|
||||||
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
|
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
|
||||||
@@ -316,7 +316,7 @@ jobs:
|
|||||||
bun-version: "1.3.14"
|
bun-version: "1.3.14"
|
||||||
|
|
||||||
- name: 💾 Cache Bun dependencies
|
- name: 💾 Cache Bun dependencies
|
||||||
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||||
with:
|
with:
|
||||||
path: ~/.bun/install/cache
|
path: ~/.bun/install/cache
|
||||||
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
|
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
|
||||||
@@ -383,7 +383,7 @@ jobs:
|
|||||||
bun-version: "1.3.14"
|
bun-version: "1.3.14"
|
||||||
|
|
||||||
- name: 💾 Cache Bun dependencies
|
- name: 💾 Cache Bun dependencies
|
||||||
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||||
with:
|
with:
|
||||||
path: ~/.bun/install/cache
|
path: ~/.bun/install/cache
|
||||||
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
|
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
|
||||||
@@ -453,7 +453,7 @@ jobs:
|
|||||||
bun-version: "1.3.14"
|
bun-version: "1.3.14"
|
||||||
|
|
||||||
- name: 💾 Cache Bun dependencies
|
- name: 💾 Cache Bun dependencies
|
||||||
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||||
with:
|
with:
|
||||||
path: ~/.bun/install/cache
|
path: ~/.bun/install/cache
|
||||||
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
|
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
|
||||||
|
|||||||
2
.github/workflows/check-lockfile.yml
vendored
2
.github/workflows/check-lockfile.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
|||||||
bun-version: "1.3.14"
|
bun-version: "1.3.14"
|
||||||
|
|
||||||
- name: 💾 Cache Bun dependencies
|
- name: 💾 Cache Bun dependencies
|
||||||
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.bun/install/cache
|
~/.bun/install/cache
|
||||||
|
|||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -77,7 +77,7 @@ jobs:
|
|||||||
bun-version: "1.3.14"
|
bun-version: "1.3.14"
|
||||||
|
|
||||||
- name: 💾 Cache Bun dependencies
|
- name: 💾 Cache Bun dependencies
|
||||||
uses: actions/cache@2c8a9bd7457de244a408f35966fab2fb45fda9c8 # v6.0.0
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||||
with:
|
with:
|
||||||
path: ~/.bun/install/cache
|
path: ~/.bun/install/cache
|
||||||
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
|
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
|
||||||
|
|||||||
@@ -893,27 +893,6 @@ export default function DirectPlayerPage() {
|
|||||||
// Check if we're transcoding
|
// Check if we're transcoding
|
||||||
const isTranscoding = Boolean(stream?.mediaSource?.TranscodingUrl);
|
const isTranscoding = Boolean(stream?.mediaSource?.TranscodingUrl);
|
||||||
|
|
||||||
// A transcoded stream only carries the audio track the server encoded
|
|
||||||
// into it — switching requires re-negotiating the stream with the new
|
|
||||||
// index (like the mobile menu's replacePlayer), not an mpv aid change.
|
|
||||||
if (isTranscoding) {
|
|
||||||
const queryParams = new URLSearchParams({
|
|
||||||
itemId: item?.Id ?? "",
|
|
||||||
audioIndex: String(index),
|
|
||||||
subtitleIndex: String(currentSubtitleIndex),
|
|
||||||
mediaSourceId: stream?.mediaSource?.Id ?? "",
|
|
||||||
bitrateValue: bitrateValue?.toString() ?? "",
|
|
||||||
playbackPosition: msToTicks(progress.get()).toString(),
|
|
||||||
}).toString();
|
|
||||||
// Destroy the current mpv instance BEFORE navigating, same rationale as
|
|
||||||
// goToNextItem/goToPreviousItem: Expo Router briefly holds two players
|
|
||||||
// during the transition, and two simultaneous decoders OOM-kill low-RAM
|
|
||||||
// devices. Resume is preserved via the playbackPosition param.
|
|
||||||
videoRef.current?.destroy().catch(() => {});
|
|
||||||
router.replace(`player/direct-player?${queryParams}` as any);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert Jellyfin index to MPV track ID
|
// Convert Jellyfin index to MPV track ID
|
||||||
const mpvTrackId = getMpvAudioId(
|
const mpvTrackId = getMpvAudioId(
|
||||||
stream?.mediaSource,
|
stream?.mediaSource,
|
||||||
@@ -925,14 +904,7 @@ export default function DirectPlayerPage() {
|
|||||||
await videoRef.current?.setAudioTrack?.(mpvTrackId);
|
await videoRef.current?.setAudioTrack?.(mpvTrackId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[stream?.mediaSource],
|
||||||
stream?.mediaSource,
|
|
||||||
item?.Id,
|
|
||||||
currentSubtitleIndex,
|
|
||||||
bitrateValue,
|
|
||||||
router,
|
|
||||||
progress,
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// TV subtitle track change handler
|
// TV subtitle track change handler
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|||||||
import {
|
import {
|
||||||
Animated,
|
Animated,
|
||||||
Easing,
|
Easing,
|
||||||
InteractionManager,
|
|
||||||
ScrollView,
|
ScrollView,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
TVFocusGuideView,
|
TVFocusGuideView,
|
||||||
@@ -76,20 +75,6 @@ export default function TVOptionModal() {
|
|||||||
}, [isReady]);
|
}, [isReady]);
|
||||||
|
|
||||||
const handleSelect = (value: any) => {
|
const handleSelect = (value: any) => {
|
||||||
if (modalState?.deferApplyUntilDismissed) {
|
|
||||||
// onSelect navigates (the transcode audio switch replacing the player);
|
|
||||||
// a router.replace fired while this modal is the active route would be
|
|
||||||
// swallowed. Close FIRST, apply after dismissal.
|
|
||||||
const onSelect = modalState.onSelect;
|
|
||||||
store.set(tvOptionModalAtom, null);
|
|
||||||
router.back();
|
|
||||||
InteractionManager.runAfterInteractions(() => onSelect?.(value));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// State-only callers (detail page, library filters, settings): run before
|
|
||||||
// closing so the re-render happens while the modal is up. Deferring it until
|
|
||||||
// after dismissal re-renders the page after focus returns and yanks TV
|
|
||||||
// focus, leaving navigation stuck.
|
|
||||||
modalState?.onSelect(value);
|
modalState?.onSelect(value);
|
||||||
store.set(tvOptionModalAtom, null);
|
store.set(tvOptionModalAtom, null);
|
||||||
router.back();
|
router.back();
|
||||||
|
|||||||
@@ -564,9 +564,6 @@ export const Controls: FC<Props> = ({
|
|||||||
title: t("item_card.audio"),
|
title: t("item_card.audio"),
|
||||||
options: audioOptions,
|
options: audioOptions,
|
||||||
onSelect: handleAudioChange,
|
onSelect: handleAudioChange,
|
||||||
// In-player audio selection navigates (replacePlayer while transcoding);
|
|
||||||
// apply it after the modal is dismissed so it isn't swallowed.
|
|
||||||
deferApplyUntilDismissed: true,
|
|
||||||
});
|
});
|
||||||
controlsInteractionRef.current();
|
controlsInteractionRef.current();
|
||||||
}, [showOptions, t, audioOptions, handleAudioChange]);
|
}, [showOptions, t, audioOptions, handleAudioChange]);
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ interface ShowOptionsParams<T> {
|
|||||||
onSelect: (value: T) => void;
|
onSelect: (value: T) => void;
|
||||||
cardWidth?: number;
|
cardWidth?: number;
|
||||||
cardHeight?: number;
|
cardHeight?: number;
|
||||||
deferApplyUntilDismissed?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useTVOptionModal = () => {
|
export const useTVOptionModal = () => {
|
||||||
@@ -27,7 +26,6 @@ export const useTVOptionModal = () => {
|
|||||||
onSelect: params.onSelect,
|
onSelect: params.onSelect,
|
||||||
cardWidth: params.cardWidth,
|
cardWidth: params.cardWidth,
|
||||||
cardHeight: params.cardHeight,
|
cardHeight: params.cardHeight,
|
||||||
deferApplyUntilDismissed: params.deferApplyUntilDismissed,
|
|
||||||
});
|
});
|
||||||
router.push("/(auth)/tv-option-modal");
|
router.push("/(auth)/tv-option-modal");
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,15 +13,6 @@ export type TVOptionModalState = {
|
|||||||
onSelect: (value: any) => void;
|
onSelect: (value: any) => void;
|
||||||
cardWidth?: number;
|
cardWidth?: number;
|
||||||
cardHeight?: number;
|
cardHeight?: number;
|
||||||
/**
|
|
||||||
* Run onSelect AFTER the modal route is dismissed. Needed only when onSelect
|
|
||||||
* navigates (the in-player audio switch replacing the player while
|
|
||||||
* transcoding), which the still-active modal route would otherwise swallow.
|
|
||||||
* Default (false) runs onSelect before closing, so state-only callers (detail
|
|
||||||
* page, library filters, settings) don't re-render after focus returns and
|
|
||||||
* lose TV focus.
|
|
||||||
*/
|
|
||||||
deferApplyUntilDismissed?: boolean;
|
|
||||||
} | null;
|
} | null;
|
||||||
|
|
||||||
export const tvOptionModalAtom = atom<TVOptionModalState>(null);
|
export const tvOptionModalAtom = atom<TVOptionModalState>(null);
|
||||||
|
|||||||
Reference in New Issue
Block a user