diff --git a/modules/mpv-player/android/src/main/java/expo/modules/mpvplayer/MPVLayerRenderer.kt b/modules/mpv-player/android/src/main/java/expo/modules/mpvplayer/MPVLayerRenderer.kt index 6b41a621..3cd6732f 100644 --- a/modules/mpv-player/android/src/main/java/expo/modules/mpvplayer/MPVLayerRenderer.kt +++ b/modules/mpv-player/android/src/main/java/expo/modules/mpvplayer/MPVLayerRenderer.kt @@ -532,16 +532,27 @@ class MPVLayerRenderer(private val context: Context) : MPVLib.EventObserver { val trackId = mpv?.getPropertyInt("track-list/$i/id") ?: continue val track = mutableMapOf("id" to trackId) - + mpv?.getPropertyString("track-list/$i/title")?.let { track["title"] = it } mpv?.getPropertyString("track-list/$i/lang")?.let { track["lang"] = it } - + mpv?.getPropertyString("track-list/$i/codec")?.let { track["codec"] = it } + + // Identity fields used to map a Jellyfin subtitle to the real track + // (instead of fragile positional counting). `external` + `external-filename` + // uniquely identify a sub-added sidecar; `ff-index` aids embedded matching. + val external = mpv?.getPropertyBoolean("track-list/$i/external") ?: false + track["external"] = external + mpv?.getPropertyString("track-list/$i/external-filename")?.let { + track["externalFilename"] = it + } + mpv?.getPropertyInt("track-list/$i/ff-index")?.let { track["ffIndex"] = it } + val selected = mpv?.getPropertyBoolean("track-list/$i/selected") ?: false track["selected"] = selected - + tracks.add(track) } - + return tracks } diff --git a/modules/mpv-player/ios/MPVLayerRenderer.swift b/modules/mpv-player/ios/MPVLayerRenderer.swift index 75bc3d9a..18b9ac4b 100644 --- a/modules/mpv-player/ios/MPVLayerRenderer.swift +++ b/modules/mpv-player/ios/MPVLayerRenderer.swift @@ -770,12 +770,32 @@ final class MPVLayerRenderer { if let lang = getStringProperty(handle: handle, name: "track-list/\(i)/lang") { track["lang"] = lang } - + + if let codec = getStringProperty(handle: handle, name: "track-list/\(i)/codec") { + track["codec"] = codec + } + + // Identity fields used to map a Jellyfin subtitle to the real track + // (instead of fragile positional counting). `external` + `external-filename` + // uniquely identify a sub-added sidecar; `ff-index` aids embedded matching. + var external: Int32 = 0 + getProperty(handle: handle, name: "track-list/\(i)/external", format: MPV_FORMAT_FLAG, value: &external) + track["external"] = external != 0 + + if let extFilename = getStringProperty(handle: handle, name: "track-list/\(i)/external-filename") { + track["externalFilename"] = extFilename + } + + var ffIndex: Int64 = 0 + if getProperty(handle: handle, name: "track-list/\(i)/ff-index", format: MPV_FORMAT_INT64, value: &ffIndex) >= 0 { + track["ffIndex"] = Int(ffIndex) + } + var selected: Int32 = 0 getProperty(handle: handle, name: "track-list/\(i)/selected", format: MPV_FORMAT_FLAG, value: &selected) track["selected"] = selected != 0 - - Logger.shared.log("getSubtitleTracks: found sub track id=\(trackId), title=\(track["title"] ?? "none"), lang=\(track["lang"] ?? "none")", type: "Info") + + Logger.shared.log("getSubtitleTracks: found sub track id=\(trackId), title=\(track["title"] ?? "none"), lang=\(track["lang"] ?? "none"), external=\(external != 0)", type: "Info") tracks.append(track) } diff --git a/modules/mpv-player/src/MpvPlayer.types.ts b/modules/mpv-player/src/MpvPlayer.types.ts index 17ee75de..ac3b7fba 100644 --- a/modules/mpv-player/src/MpvPlayer.types.ts +++ b/modules/mpv-player/src/MpvPlayer.types.ts @@ -141,6 +141,14 @@ export type SubtitleTrack = { id: number; title?: string; lang?: string; + /** Subtitle codec (mpv `codec`), e.g. "subrip", "ass", "hdmv_pgs_subtitle". */ + codec?: string; + /** True if loaded from a separate file via `sub-add` (mpv `external`). */ + external?: boolean; + /** For external tracks: the exact URL/path it was loaded from (mpv `external-filename`). */ + externalFilename?: string; + /** FFmpeg stream index (mpv `ff-index`); not guaranteed for non-lavf demuxers. */ + ffIndex?: number; selected?: boolean; };