mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-08-04 18:42:34 +00:00
feat: pass currently selected or last selected subtitle to external players
This commit is contained in:
parent
00cc012193
commit
615fa43f5a
9 changed files with 53 additions and 9 deletions
|
|
@ -109,6 +109,7 @@ internal actual object ExternalPlayerPlatform {
|
|||
val subtitles = request.subtitles
|
||||
if (!subtitles.isNullOrEmpty()) {
|
||||
val subtitleUris = subtitles.map { Uri.parse(it.url) }.toTypedArray()
|
||||
val subtitleCurrentOrFirstUri = request.currentSubtitle?.url ?: subtitles.first().url
|
||||
val subtitleNames = subtitles.map { it.name }.toTypedArray()
|
||||
val subtitleFilenames = subtitles.map { "${it.lang}_${it.name}.srt" }.toTypedArray()
|
||||
|
||||
|
|
@ -120,7 +121,7 @@ internal actual object ExternalPlayerPlatform {
|
|||
val clipData = android.content.ClipData(
|
||||
"subtitles",
|
||||
arrayOf("application/x-subrip", "text/vtt"),
|
||||
android.content.ClipData.Item(subtitleUris.first())
|
||||
android.content.ClipData.Item(subtitleCurrentOrFirstUri)
|
||||
)
|
||||
subtitleUris.drop(1).forEach { subtitleUri ->
|
||||
clipData.addItem(android.content.ClipData.Item(subtitleUri))
|
||||
|
|
@ -131,17 +132,17 @@ internal actual object ExternalPlayerPlatform {
|
|||
putExtra("subs", subtitleUris)
|
||||
putExtra("subs.name", subtitleNames)
|
||||
putExtra("subs.filename", subtitleFilenames)
|
||||
putExtra("subs.enable", arrayOf(subtitleUris.first()))
|
||||
putExtra("subs.enable", arrayOf(subtitleCurrentOrFirstUri))
|
||||
|
||||
// Just Player
|
||||
putExtra("subtitle_uri", subtitleUris)
|
||||
putExtra("subtitle_name", subtitleNames)
|
||||
|
||||
// VLC (single subtitle — use first one)
|
||||
putExtra("subtitles_location", subtitleUris.first())
|
||||
// VLC (single subtitle — use selected one)
|
||||
putExtra("subtitles_location", subtitleCurrentOrFirstUri)
|
||||
|
||||
// Vimu Player
|
||||
putExtra("forcedsrt", subtitles.first().url)
|
||||
putExtra("forcedsrt", subtitleCurrentOrFirstUri)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -176,9 +176,11 @@ import com.nuvio.app.features.player.PlayerPlaybackSnapshot
|
|||
import com.nuvio.app.features.player.ExternalPlayerIntentResult
|
||||
import com.nuvio.app.features.player.ExternalPlayerPlatform
|
||||
import com.nuvio.app.features.player.ExternalPlayerPlaybackRequest
|
||||
import com.nuvio.app.features.player.SubtitleInput
|
||||
import com.nuvio.app.features.player.rememberExternalPlayerLauncher
|
||||
import com.nuvio.app.features.player.prepareExternalPlayerLaunch
|
||||
import com.nuvio.app.features.player.SubtitleLanguageOption
|
||||
import com.nuvio.app.features.streams.StreamSubtitle
|
||||
import com.nuvio.app.features.player.sanitizePlaybackHeaders
|
||||
import com.nuvio.app.features.player.sanitizePlaybackResponseHeaders
|
||||
import com.nuvio.app.features.profiles.AvatarRepository
|
||||
|
|
@ -394,6 +396,14 @@ private fun PlayerLaunch.toExternalPlayerPlaybackRequest(): ExternalPlayerPlayba
|
|||
season = seasonNumber,
|
||||
episode = episodeNumber,
|
||||
episodeTitle = episodeTitle,
|
||||
currentSubtitle = currentSubtitle,
|
||||
subtitles = externalSubtitles.map { sub: StreamSubtitle ->
|
||||
SubtitleInput(
|
||||
url = sub.url,
|
||||
name = sub.name ?: sub.language,
|
||||
lang = sub.language
|
||||
)
|
||||
}.takeIf { it.isNotEmpty() }
|
||||
)
|
||||
|
||||
private enum class AppGateScreen {
|
||||
|
|
@ -1398,6 +1408,7 @@ private fun MainAppContent(
|
|||
request = baseRequest,
|
||||
type = launch.contentType ?: launch.parentMetaType,
|
||||
videoId = launch.videoId ?: launch.parentMetaId,
|
||||
parentMetaId = launch.parentMetaId,
|
||||
forwardSubtitles = playerSettingsUiState.externalPlayerForwardSubtitles,
|
||||
sendSkipSegments = shouldSendSkipSegments,
|
||||
preferredLanguage = playerSettingsUiState.preferredSubtitleLanguage,
|
||||
|
|
@ -2983,6 +2994,7 @@ private fun MainAppContent(
|
|||
parentMetaId = launch.parentMetaId,
|
||||
parentMetaType = launch.parentMetaType,
|
||||
initialPositionMs = request.resumePositionMs,
|
||||
currentSubtitle = request.currentSubtitle,
|
||||
)
|
||||
lastExternalPlayerLaunch = playerLaunch
|
||||
val intentResult = ExternalPlayerPlatform.buildIntent(
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ suspend fun prepareExternalPlayerLaunch(
|
|||
request: ExternalPlayerPlaybackRequest,
|
||||
type: String,
|
||||
videoId: String,
|
||||
parentMetaId: String,
|
||||
forwardSubtitles: Boolean,
|
||||
sendSkipSegments: Boolean,
|
||||
preferredLanguage: String,
|
||||
|
|
@ -48,6 +49,7 @@ suspend fun prepareExternalPlayerLaunch(
|
|||
val subtitles = SubtitleForwarder.fetchForExternalPlayer(
|
||||
type = type,
|
||||
videoId = videoId,
|
||||
parentMetaId = parentMetaId,
|
||||
preferredLanguage = preferredLanguage,
|
||||
secondaryLanguage = secondaryLanguage,
|
||||
)
|
||||
|
|
@ -78,6 +80,17 @@ suspend fun prepareExternalPlayerLaunch(
|
|||
result = result.copy(skipSegmentsJson = skipSegmentsJson)
|
||||
}
|
||||
|
||||
val preference = PlayerTrackPreferenceStorage.load(parentMetaId)
|
||||
if (result.currentSubtitle == null && preference != null) {
|
||||
val match = result.subtitles?.find {
|
||||
it.url == preference.addonSubtitleUrl ||
|
||||
(it.name == preference.subtitleName && it.lang == preference.subtitleLanguage)
|
||||
}
|
||||
if (match != null) {
|
||||
result = result.copy(currentSubtitle = match)
|
||||
}
|
||||
}
|
||||
|
||||
return@coroutineScope result
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ data class ExternalPlayerPlaybackRequest(
|
|||
val sourceHeaders: Map<String, String> = emptyMap(),
|
||||
val resumePositionMs: Long = 0L,
|
||||
val subtitles: List<SubtitleInput>? = null,
|
||||
val currentSubtitle: SubtitleInput? = null,
|
||||
val season: Int? = null,
|
||||
val episode: Int? = null,
|
||||
val episodeTitle: String? = null,
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ data class PlayerLaunch(
|
|||
val initialPositionMs: Long = 0L,
|
||||
val initialProgressFraction: Float? = null,
|
||||
val contentLanguage: String? = null,
|
||||
val currentSubtitle: SubtitleInput? = null,
|
||||
)
|
||||
|
||||
object PlayerLaunchStore {
|
||||
|
|
|
|||
|
|
@ -39,4 +39,5 @@ internal data class PlayerScreenArgs(
|
|||
val initialPositionMs: Long,
|
||||
val initialProgressFraction: Float?,
|
||||
val contentLanguage: String? = null,
|
||||
val currentSubtitle: SubtitleInput? = null,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -308,6 +308,13 @@ private fun PlayerScreenRuntime.RenderPlayerControls(displayedPositionMs: Long,
|
|||
sourceHeaders = activeSourceHeaders,
|
||||
resumePositionMs = playbackSnapshot.positionMs,
|
||||
subtitles = loadedSubtitles,
|
||||
currentSubtitle = selectedAddonSubtitle?.let {
|
||||
SubtitleInput(
|
||||
it.url,
|
||||
it.display,
|
||||
it.language
|
||||
)
|
||||
},
|
||||
season = activeSeasonNumber,
|
||||
episode = activeEpisodeNumber,
|
||||
episodeTitle = activeEpisodeTitle,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ object SubtitleForwarder {
|
|||
suspend fun fetchForExternalPlayer(
|
||||
type: String,
|
||||
videoId: String,
|
||||
parentMetaId: String,
|
||||
preferredLanguage: String,
|
||||
secondaryLanguage: String?,
|
||||
timeoutMs: Long = 10_000L,
|
||||
|
|
@ -31,11 +32,18 @@ object SubtitleForwarder {
|
|||
}
|
||||
|
||||
val allSubtitles = SubtitleRepository.addonSubtitles.value
|
||||
val preference = PlayerTrackPreferenceStorage.load(parentMetaId)
|
||||
|
||||
val filtered = allSubtitles.filter { subtitle ->
|
||||
languageMatchesPreference(subtitle.language, preferredLanguage) ||
|
||||
(secondaryLanguage != null &&
|
||||
languageMatchesPreference(subtitle.language, secondaryLanguage))
|
||||
val isLastSelected = preference != null && (
|
||||
subtitle.url == preference.addonSubtitleUrl ||
|
||||
(subtitle.display == preference.subtitleName && subtitle.language == preference.subtitleLanguage)
|
||||
)
|
||||
|
||||
isLastSelected ||
|
||||
languageMatchesPreference(subtitle.language, preferredLanguage) ||
|
||||
(secondaryLanguage != null &&
|
||||
languageMatchesPreference(subtitle.language, secondaryLanguage))
|
||||
}
|
||||
|
||||
filtered.map { subtitle ->
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ private val iosExternalPlayerSpecs = listOf(
|
|||
buildString {
|
||||
append("vlc-x-callback://x-callback-url/stream?url=")
|
||||
append(request.sourceUrl.urlQueryEncode())
|
||||
request.subtitles?.firstOrNull()?.let { subtitle ->
|
||||
(request.currentSubtitle ?: request.subtitles?.firstOrNull())?.let { subtitle ->
|
||||
append("&sub=")
|
||||
append(subtitle.url.urlQueryEncode())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue