Compare commits

..

2 Commits

Author SHA1 Message Date
Lance Chant
d6980cfc8e fix: subtitle ordering
Fixed an issue where external and subrip subtitles were not ordered
correctly

Signed-off-by: Lance Chant <13349722+lancechant@users.noreply.github.com>
2026-06-23 12:00:11 +02:00
Niyazaki
b256e99fc8 fix(search): set typed text color on Android search bar (#1756)
Some checks are pending
🏗️ Build Apps / 🤖 Build Android APK (Phone) (push) Waiting to run
🏗️ Build Apps / 🤖 Build Android APK (TV) (push) Waiting to run
🏗️ Build Apps / 🍎 Build iOS IPA (Phone) (push) Waiting to run
🏗️ Build Apps / 🍎 Build iOS IPA (Phone - Unsigned) (push) Waiting to run
🏗️ Build Apps / 🍎 Build tvOS IPA (push) Waiting to run
🔒 Lockfile Consistency Check / 🔍 Check bun.lock and package.json consistency (push) Waiting to run
🛡️ CodeQL Analysis / 🔎 Analyze with CodeQL (actions) (push) Waiting to run
🏷️🔀Merge Conflict Labeler / 🏷️ Labeling Merge Conflicts (push) Waiting to run
🚦 Security & Quality Gate / 📝 Validate PR Title (push) Waiting to run
🚦 Security & Quality Gate / 🔍 Vulnerable Dependencies (push) Waiting to run
🚦 Security & Quality Gate / 🚑 Expo Doctor Check (push) Waiting to run
🚦 Security & Quality Gate / 🔍 Lint & Test (check) (push) Waiting to run
🚦 Security & Quality Gate / 🔍 Lint & Test (format) (push) Waiting to run
🚦 Security & Quality Gate / 🔍 Lint & Test (i18n:check) (push) Waiting to run
🏗️ Build Apps / 🍎 Build tvOS IPA (Unsigned) (push) Waiting to run
🛡️ CodeQL Analysis / 🔎 Analyze with CodeQL (javascript-typescript) (push) Waiting to run
🚦 Security & Quality Gate / 🔍 Lint & Test (lint) (push) Waiting to run
🚦 Security & Quality Gate / 🔍 Lint & Test (typecheck) (push) Waiting to run
🛡️ Trivy Security Scan / 🔎 Filesystem scan (push) Waiting to run
2026-06-23 09:11:38 +02:00
4 changed files with 47 additions and 12 deletions

View File

@@ -305,6 +305,8 @@ export default function SearchPage() {
},
hideWhenScrolling: false,
autoFocus: false,
// Android: color of the user-typed text (was dark and unreadable on the dark header)
textColor: "#fff",
// Android: placeholder and icon color
hintTextColor: "#fff",
headerIconColor: "#fff",

View File

@@ -69,7 +69,7 @@
"react-native-device-info": "^15.0.0",
"react-native-draggable-flatlist": "^4.0.3",
"react-native-edge-to-edge": "^1.7.0",
"react-native-gesture-handler": "~3.0.0",
"react-native-gesture-handler": "~2.31.1",
"react-native-glass-effect-view": "^1.0.0",
"react-native-google-cast": "^4.9.1",
"react-native-image-colors": "^2.4.0",
@@ -290,6 +290,8 @@
"@douglowder/expo-av-route-picker-view": ["@douglowder/expo-av-route-picker-view@0.0.5", "", { "peerDependencies": { "expo": "*", "react": "*" } }, "sha512-oT4wf8aYYNfLEuZEkwZIH7CtEHKnEHWnjs6/hNwbFGEC0FnfjjWBNrQEt4fo5/gkafqa2G5ILkxndMyBZvk5dg=="],
"@egjs/hammerjs": ["@egjs/hammerjs@2.0.17", "", { "dependencies": { "@types/hammerjs": "^2.0.36" } }, "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A=="],
"@epic-web/invariant": ["@epic-web/invariant@1.0.0", "", {}, "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA=="],
"@expo-google-fonts/material-symbols": ["@expo-google-fonts/material-symbols@0.4.38", "", {}, "sha512-IJkBtN1o8u9BW5fvSii1MyHPQ7Q0HxbWcVBvOrOzgMLpVtZw7R2w94wBTVR7kZwv3w1JNTESMmLA5Sqn1+Z36A=="],
@@ -576,6 +578,8 @@
"@types/emscripten": ["@types/emscripten@1.41.5", "", {}, "sha512-cMQm7pxu6BxtHyqJ7mQZ2kXWV5SLmugybFdHCBbJ5eHzOo6VhBckEgAT3//rP5FwPHNPeEiq4SmQ5ucBwsOo4Q=="],
"@types/hammerjs": ["@types/hammerjs@2.0.46", "", {}, "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw=="],
"@types/hoist-non-react-statics": ["@types/hoist-non-react-statics@3.3.7", "", { "dependencies": { "hoist-non-react-statics": "^3.3.0" }, "peerDependencies": { "@types/react": "*" } }, "sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g=="],
"@types/istanbul-lib-coverage": ["@types/istanbul-lib-coverage@2.0.6", "", {}, "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w=="],
@@ -1546,7 +1550,7 @@
"react-native-edge-to-edge": ["react-native-edge-to-edge@1.8.1", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-bhvsKqeX9PGkY9wBUk9vni/tJNJdKtLPbs/j3e/3CdV4JmUWfTXYYoL+4Hc8Wmej+5eJxkc8KOFa454ruFWBCA=="],
"react-native-gesture-handler": ["react-native-gesture-handler@3.0.2", "", { "dependencies": { "@types/react-test-renderer": "^19.1.0", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-XBTgmvr2jh/xrMwlHTV2Z1x6IFUl3zfLxyaCAnvj3GSXK5YlY3ZmiIs57hniPmh3I7RtjPFxtGdRr0i+PzyBrg=="],
"react-native-gesture-handler": ["react-native-gesture-handler@2.31.2", "", { "dependencies": { "@egjs/hammerjs": "^2.0.17", "@types/react-test-renderer": "^19.1.0", "hoist-non-react-statics": "^3.3.0", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-rw5q74i2AfS7YGYdbxQDhOU7xqgY6WRM1132/CCm3erqjblhECZDZFHIm0tteHoC9ih24wogVBVVzcTBQtZ+5A=="],
"react-native-glass-effect-view": ["react-native-glass-effect-view@1.0.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-ABYG0oIiqbXsxe2R/cMhNgDn3YgwDLz/2TIN2XOxQopXC+MiGsG9C32VYQvO2sYehcu5JmI3h3EzwLwl6lJhhA=="],

View File

@@ -92,7 +92,7 @@
"react-native-device-info": "^15.0.0",
"react-native-draggable-flatlist": "^4.0.3",
"react-native-edge-to-edge": "^1.7.0",
"react-native-gesture-handler": "~3.0.0",
"react-native-gesture-handler": "~2.31.1",
"react-native-glass-effect-view": "^1.0.0",
"react-native-google-cast": "^4.9.1",
"react-native-image-colors": "^2.4.0",

View File

@@ -44,9 +44,22 @@ export const isSubtitleInMpv = (
/**
* Calculate the MPV track ID for a given Jellyfin subtitle index.
*
* MPV track IDs are 1-based and only count subtitles that are actually in MPV.
* We iterate through all subtitles, counting only those in MPV, until we find
* the one matching the Jellyfin index.
* MPV track IDs are 1-based, but MPV's track list is NOT in MediaStreams order:
* 1. Embedded/HLS subs are enumerated from the container (or HLS playlist)
* first, in MediaStreams order.
* 2. External subs are appended via `sub-add` AFTER the file loads, in the
* order they are passed to MPV (here, also MediaStreams order — see
* direct-player.tsx where the externalSubtitles array is built by
* filtering MediaStreams).
*
* Iterating in pure MediaStreams order produces the wrong MPV ID whenever an
* External sub is listed before an Embed sub in MediaStreams (common when
* Jellyfin prepends a converted SRT/VTT ahead of an original PGS/ASS track),
* causing e.g. English to select Spanish. We therefore count in two phases
* that mirror MPV's actual ordering.
*
* Image-based subs (PGS/VOBSUB) during transcoding are burned into the video
* and absent from MPV's track list; they are skipped in both phases.
*
* @param mediaSource - The media source containing subtitle streams
* @param jellyfinSubtitleIndex - The Jellyfin server-side subtitle index (-1 = disabled)
@@ -74,14 +87,30 @@ export const getMpvSubtitleId = (
return undefined;
}
// Count MPV track position (1-based)
const isExternal = (sub: MediaStream) =>
sub.DeliveryMethod === SubtitleDeliveryMethod.External;
let mpvIndex = 0;
// Phase 1: embedded / HLS subs — these occupy MPV track IDs first because
// they come from the container or HLS playlist.
for (const sub of allSubs) {
if (isSubtitleInMpv(sub, isTranscoding)) {
mpvIndex++;
if (sub.Index === jellyfinSubtitleIndex) {
return mpvIndex;
}
if (isExternal(sub)) continue;
if (!isSubtitleInMpv(sub, isTranscoding)) continue;
mpvIndex++;
if (sub.Index === jellyfinSubtitleIndex) {
return mpvIndex;
}
}
// Phase 2: external subs — appended via `sub-add` after the file loads,
// so they come last in MPV's track list.
for (const sub of allSubs) {
if (!isExternal(sub)) continue;
if (!isSubtitleInMpv(sub, isTranscoding)) continue;
mpvIndex++;
if (sub.Index === jellyfinSubtitleIndex) {
return mpvIndex;
}
}