feat(macos): player functionality with new callbacks

This commit is contained in:
tapframe 2026-04-18 01:06:28 +05:30
parent 859027f3fd
commit da1b83c3b7
5 changed files with 407 additions and 14 deletions

2
MPVKit

@ -1 +1 @@
Subproject commit 61e0e8683f0558fe3ff2299b1fbfd97799a2474d Subproject commit a633ca46a3d9713e6edc885ef0e17448054997f7

View file

@ -28,6 +28,7 @@ interface PlayerEngineController {
artwork: String? = null, artwork: String? = null,
logo: String? = null, logo: String? = null,
) {} ) {}
fun setPlayerFlags(hasVideoId: Boolean, isSeries: Boolean) {}
fun showSkipButton(type: String, endTimeMs: Long) {} fun showSkipButton(type: String, endTimeMs: Long) {}
fun hideSkipButton() {} fun hideSkipButton() {}
fun showNextEpisode( fun showNextEpisode(
@ -39,6 +40,35 @@ interface PlayerEngineController {
) {} ) {}
fun hideNextEpisode() {} fun hideNextEpisode() {}
fun setOnCloseCallback(callback: () -> Unit) {} fun setOnCloseCallback(callback: () -> Unit) {}
fun setOnAddonSubtitlesFetchCallback(callback: () -> Unit) {}
fun pushAddonSubtitles(subtitles: List<AddonSubtitle>, isLoading: Boolean) {}
fun setOnSourcesRequestedCallback(callback: () -> Unit) {}
fun setOnSourceStreamSelectedCallback(callback: (String) -> Unit) {}
fun setOnSourceFilterChangedCallback(callback: (String?) -> Unit) {}
fun setOnSourceReloadCallback(callback: () -> Unit) {}
fun setOnEpisodesRequestedCallback(callback: () -> Unit) {}
fun setOnEpisodeSelectedCallback(callback: (String) -> Unit) {}
fun setOnEpisodeStreamSelectedCallback(callback: (String) -> Unit) {}
fun setOnEpisodeFilterChangedCallback(callback: (String?) -> Unit) {}
fun setOnEpisodeReloadCallback(callback: () -> Unit) {}
fun setOnEpisodeBackCallback(callback: () -> Unit) {}
fun pushSourceData(
streams: List<com.nuvio.app.features.streams.StreamItem>,
groups: List<com.nuvio.app.features.streams.AddonStreamGroup>,
loading: Boolean,
selectedFilter: String?,
currentStreamUrl: String?,
) {}
fun pushEpisodes(episodes: List<com.nuvio.app.features.details.MetaVideo>) {}
fun pushEpisodeStreamsData(
streams: List<com.nuvio.app.features.streams.StreamItem>,
groups: List<com.nuvio.app.features.streams.AddonStreamGroup>,
loading: Boolean,
selectedFilter: String?,
currentStreamUrl: String?,
) {}
fun showEpisodeStreamsView(season: Int?, episode: Int?, title: String?) {}
fun switchSource(url: String, audioUrl: String?, headersJson: String?) {}
} }
internal fun sanitizePlaybackHeaders(headers: Map<String, String>?): Map<String, String> { internal fun sanitizePlaybackHeaders(headers: Map<String, String>?): Map<String, String> {

View file

@ -1023,6 +1023,30 @@ fun PlayerScreen(
playerController?.applySubtitleStyle(subtitleStyle) playerController?.applySubtitleStyle(subtitleStyle)
} }
LaunchedEffect(playerController, addonSubtitles, isLoadingAddonSubtitles) {
playerController?.pushAddonSubtitles(addonSubtitles, isLoadingAddonSubtitles)
}
LaunchedEffect(playerController, sourceStreamsState) {
playerController?.pushSourceData(
streams = sourceStreamsState.allStreams,
groups = sourceStreamsState.groups,
loading = sourceStreamsState.isAnyLoading,
selectedFilter = sourceStreamsState.selectedFilter,
currentStreamUrl = activeSourceUrl,
)
}
LaunchedEffect(playerController, episodeStreamsRepoState) {
playerController?.pushEpisodeStreamsData(
streams = episodeStreamsRepoState.allStreams,
groups = episodeStreamsRepoState.groups,
loading = episodeStreamsRepoState.isAnyLoading,
selectedFilter = episodeStreamsRepoState.selectedFilter,
currentStreamUrl = activeSourceUrl,
)
}
LaunchedEffect(playbackSnapshot.isLoading, playerController) { LaunchedEffect(playbackSnapshot.isLoading, playerController) {
if (!playbackSnapshot.isLoading && playerController != null) { if (!playbackSnapshot.isLoading && playerController != null) {
refreshTracks() refreshTracks()
@ -1441,7 +1465,124 @@ fun PlayerScreen(
artwork = backdropArtwork, artwork = backdropArtwork,
logo = logo, logo = logo,
) )
controller.setPlayerFlags(
hasVideoId = activeVideoId != null,
isSeries = parentMetaType == "series",
)
controller.setOnCloseCallback { onBackWithProgress() } controller.setOnCloseCallback { onBackWithProgress() }
controller.setOnAddonSubtitlesFetchCallback {
if (contentType != null && activeVideoId != null) {
SubtitleRepository.fetchAddonSubtitles(contentType, activeVideoId!!)
}
}
controller.setOnSourcesRequestedCallback {
val type = contentType ?: parentMetaType
val vid = activeVideoId ?: return@setOnSourcesRequestedCallback
PlayerStreamsRepository.loadSources(
type = type,
videoId = vid,
season = activeSeasonNumber,
episode = activeEpisodeNumber,
)
}
controller.setOnSourceStreamSelectedCallback { url ->
val allStreams = PlayerStreamsRepository.sourceState.value.allStreams
val stream = allStreams.firstOrNull { it.directPlaybackUrl == url }
?: return@setOnSourceStreamSelectedCallback
switchToSource(stream)
val headers = sanitizePlaybackHeaders(stream.behaviorHints.proxyHeaders?.request)
val headersJson = headers.takeIf { it.isNotEmpty() }?.entries
?.joinToString(",", "{", "}") { (k, v) -> "\"${k}\":\"${v}\"" }
controller.switchSource(url, null, headersJson)
controller.setMetadata(
title = title,
streamTitle = activeStreamTitle,
providerName = activeProviderName,
seasonNumber = activeSeasonNumber,
episodeNumber = activeEpisodeNumber,
episodeTitle = activeEpisodeTitle,
artwork = backdropArtwork,
logo = logo,
)
}
controller.setOnSourceFilterChangedCallback { addonId ->
PlayerStreamsRepository.selectSourceFilter(addonId)
}
controller.setOnSourceReloadCallback {
val type = contentType ?: parentMetaType
val vid = activeVideoId ?: return@setOnSourceReloadCallback
PlayerStreamsRepository.loadSources(
type = type,
videoId = vid,
season = activeSeasonNumber,
episode = activeEpisodeNumber,
forceRefresh = true,
)
}
controller.setOnEpisodesRequestedCallback {
scope.launch {
if (playerMetaVideos.isEmpty()) {
playerMetaVideos = MetaDetailsRepository.fetch(parentMetaType, parentMetaId)?.videos ?: emptyList()
}
controller.pushEpisodes(playerMetaVideos)
}
}
controller.setOnEpisodeSelectedCallback { episodeId ->
val episode = playerMetaVideos.firstOrNull { it.id == episodeId }
?: return@setOnEpisodeSelectedCallback
episodeStreamsPanelState = episodeStreamsPanelState.copy(
showStreams = true,
selectedEpisode = episode,
)
val type = contentType ?: parentMetaType
PlayerStreamsRepository.loadEpisodeStreams(
type = type,
videoId = episode.id,
season = episode.season,
episode = episode.episode,
)
controller.showEpisodeStreamsView(episode.season, episode.episode, episode.title)
}
controller.setOnEpisodeStreamSelectedCallback { url ->
val allStreams = PlayerStreamsRepository.episodeStreamsState.value.allStreams
val stream = allStreams.firstOrNull { it.directPlaybackUrl == url }
?: return@setOnEpisodeStreamSelectedCallback
val episode = playerMetaVideos.firstOrNull { it.id == episodeStreamsPanelState.selectedEpisode?.id }
?: return@setOnEpisodeStreamSelectedCallback
switchToEpisodeStream(stream, episode)
val headers = sanitizePlaybackHeaders(stream.behaviorHints.proxyHeaders?.request)
val headersJson = headers.takeIf { it.isNotEmpty() }?.entries
?.joinToString(",", "{", "}") { (k, v) -> "\"${k}\":\"${v}\"" }
controller.switchSource(url, null, headersJson)
controller.setMetadata(
title = title,
streamTitle = activeStreamTitle,
providerName = activeProviderName,
seasonNumber = activeSeasonNumber,
episodeNumber = activeEpisodeNumber,
episodeTitle = activeEpisodeTitle,
artwork = backdropArtwork,
logo = logo,
)
}
controller.setOnEpisodeFilterChangedCallback { addonId ->
PlayerStreamsRepository.selectEpisodeStreamsFilter(addonId)
}
controller.setOnEpisodeReloadCallback {
val episode = episodeStreamsPanelState.selectedEpisode ?: return@setOnEpisodeReloadCallback
val type = contentType ?: parentMetaType
PlayerStreamsRepository.loadEpisodeStreams(
type = type,
videoId = episode.id,
season = episode.season,
episode = episode.episode,
forceRefresh = true,
)
}
controller.setOnEpisodeBackCallback {
episodeStreamsPanelState = EpisodeStreamsPanelState()
PlayerStreamsRepository.clearEpisodeStreams()
}
}, },
onSnapshot = { snapshot -> onSnapshot = { snapshot ->
playbackSnapshot = snapshot playbackSnapshot = snapshot

View file

@ -52,6 +52,9 @@ internal interface DesktopMPVBridgeLib : Library {
logo: String?, logo: String?,
) )
fun nuvio_player_set_has_video_id(player: Pointer, value: Boolean)
fun nuvio_player_set_is_series(player: Pointer, value: Boolean)
fun nuvio_player_load_file( fun nuvio_player_load_file(
player: Pointer, player: Pointer,
url: String, url: String,
@ -117,4 +120,43 @@ internal interface DesktopMPVBridgeLib : Library {
fun nuvio_player_is_closed(player: Pointer): Boolean fun nuvio_player_is_closed(player: Pointer): Boolean
fun nuvio_player_pop_next_episode_pressed(player: Pointer): Boolean fun nuvio_player_pop_next_episode_pressed(player: Pointer): Boolean
fun nuvio_player_is_addon_subtitles_fetch_requested(player: Pointer): Boolean
fun nuvio_player_set_addon_subtitles_loading(player: Pointer, loading: Boolean)
fun nuvio_player_clear_addon_subtitles(player: Pointer)
fun nuvio_player_add_addon_subtitle(player: Pointer, id: String, url: String, language: String, display: String)
fun nuvio_player_pop_subtitle_style_changed(player: Pointer): Boolean
fun nuvio_player_get_subtitle_style_color_index(player: Pointer): Int
fun nuvio_player_get_subtitle_style_font_size(player: Pointer): Int
fun nuvio_player_get_subtitle_style_outline_enabled(player: Pointer): Boolean
fun nuvio_player_get_subtitle_style_bottom_offset(player: Pointer): Int
fun nuvio_player_pop_sources_open_requested(player: Pointer): Boolean
fun nuvio_player_pop_episodes_open_requested(player: Pointer): Boolean
fun nuvio_player_pop_source_stream_selected(player: Pointer): String?
fun nuvio_player_pop_source_filter_changed(player: Pointer): Boolean
fun nuvio_player_get_source_filter_value(player: Pointer): String?
fun nuvio_player_pop_source_reload(player: Pointer): Boolean
fun nuvio_player_pop_episode_selected(player: Pointer): String?
fun nuvio_player_pop_episode_stream_selected(player: Pointer): String?
fun nuvio_player_pop_episode_filter_changed(player: Pointer): Boolean
fun nuvio_player_get_episode_filter_value(player: Pointer): String?
fun nuvio_player_pop_episode_reload(player: Pointer): Boolean
fun nuvio_player_pop_episode_back(player: Pointer): Boolean
fun nuvio_player_set_sources_loading(player: Pointer, loading: Boolean)
fun nuvio_player_clear_source_streams(player: Pointer)
fun nuvio_player_add_source_stream(player: Pointer, id: String, label: String, subtitle: String?, addonName: String, addonId: String, url: String, isCurrent: Boolean)
fun nuvio_player_clear_source_addon_groups(player: Pointer)
fun nuvio_player_add_source_addon_group(player: Pointer, id: String, addonName: String, addonId: String, isLoading: Boolean, hasError: Boolean)
fun nuvio_player_set_source_selected_filter(player: Pointer, addonId: String?)
fun nuvio_player_clear_episodes(player: Pointer)
fun nuvio_player_add_episode(player: Pointer, id: String, title: String, overview: String?, thumbnail: String?, season: Int, episode: Int)
fun nuvio_player_set_episode_streams_loading(player: Pointer, loading: Boolean)
fun nuvio_player_clear_episode_streams(player: Pointer)
fun nuvio_player_add_episode_stream(player: Pointer, id: String, label: String, subtitle: String?, addonName: String, addonId: String, url: String, isCurrent: Boolean)
fun nuvio_player_clear_episode_addon_groups(player: Pointer)
fun nuvio_player_add_episode_addon_group(player: Pointer, id: String, addonName: String, addonId: String, isLoading: Boolean, hasError: Boolean)
fun nuvio_player_set_episode_selected_filter(player: Pointer, addonId: String?)
fun nuvio_player_show_episode_streams(player: Pointer, season: Int, episode: Int, title: String?)
} }

View file

@ -25,6 +25,9 @@ import com.nuvio.app.core.sync.encodeSyncInt
import com.nuvio.app.core.sync.encodeSyncString import com.nuvio.app.core.sync.encodeSyncString
import com.nuvio.app.core.sync.encodeSyncStringSet import com.nuvio.app.core.sync.encodeSyncStringSet
import com.nuvio.app.desktop.DesktopPreferences import com.nuvio.app.desktop.DesktopPreferences
import com.nuvio.app.features.details.MetaVideo
import com.nuvio.app.features.streams.AddonStreamGroup
import com.nuvio.app.features.streams.StreamItem
import com.sun.jna.Pointer import com.sun.jna.Pointer
import java.util.Locale import java.util.Locale
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -50,6 +53,17 @@ actual fun PlatformPlayerSurface(
val bridge = remember { DesktopMPVBridgeLib.INSTANCE } val bridge = remember { DesktopMPVBridgeLib.INSTANCE }
val playerPtr = remember { bridge.nuvio_player_create() } val playerPtr = remember { bridge.nuvio_player_create() }
var onCloseCallback by remember { mutableStateOf<(() -> Unit)?>(null) } var onCloseCallback by remember { mutableStateOf<(() -> Unit)?>(null) }
var onAddonSubtitlesFetchCallback by remember { mutableStateOf<(() -> Unit)?>(null) }
var onSourcesRequestedCallback by remember { mutableStateOf<(() -> Unit)?>(null) }
var onSourceStreamSelectedCallback by remember { mutableStateOf<((String) -> Unit)?>(null) }
var onSourceFilterChangedCallback by remember { mutableStateOf<((String?) -> Unit)?>(null) }
var onSourceReloadCallback by remember { mutableStateOf<(() -> Unit)?>(null) }
var onEpisodesRequestedCallback by remember { mutableStateOf<(() -> Unit)?>(null) }
var onEpisodeSelectedCallback by remember { mutableStateOf<((String) -> Unit)?>(null) }
var onEpisodeStreamSelectedCallback by remember { mutableStateOf<((String) -> Unit)?>(null) }
var onEpisodeFilterChangedCallback by remember { mutableStateOf<((String?) -> Unit)?>(null) }
var onEpisodeReloadCallback by remember { mutableStateOf<(() -> Unit)?>(null) }
var onEpisodeBackCallback by remember { mutableStateOf<(() -> Unit)?>(null) }
DisposableEffect(playerPtr) { DisposableEffect(playerPtr) {
bridge.nuvio_player_show(playerPtr) bridge.nuvio_player_show(playerPtr)
@ -151,8 +165,9 @@ actual fun PlatformPlayerSurface(
override fun applySubtitleStyle(style: SubtitleStyleState) { override fun applySubtitleStyle(style: SubtitleStyleState) {
val colorHex = style.textColor.toMpvColorString() val colorHex = style.textColor.toMpvColorString()
val outline = if (style.outlineEnabled) 2.0f else 0.0f val outline = if (style.outlineEnabled) 2.0f else 0.0f
val subPos = 100 - style.bottomOffset
bridge.nuvio_player_apply_subtitle_style( bridge.nuvio_player_apply_subtitle_style(
playerPtr, colorHex, outline, style.fontSizeSp.toFloat(), style.bottomOffset, playerPtr, colorHex, outline, style.fontSizeSp.toFloat(), subPos,
) )
} }
@ -173,6 +188,11 @@ actual fun PlatformPlayerSurface(
) )
} }
override fun setPlayerFlags(hasVideoId: Boolean, isSeries: Boolean) {
bridge.nuvio_player_set_has_video_id(playerPtr, hasVideoId)
bridge.nuvio_player_set_is_series(playerPtr, isSeries)
}
override fun showSkipButton(type: String, endTimeMs: Long) { override fun showSkipButton(type: String, endTimeMs: Long) {
bridge.nuvio_player_show_skip_button(playerPtr, type, endTimeMs) bridge.nuvio_player_show_skip_button(playerPtr, type, endTimeMs)
} }
@ -198,6 +218,130 @@ actual fun PlatformPlayerSurface(
override fun setOnCloseCallback(callback: () -> Unit) { override fun setOnCloseCallback(callback: () -> Unit) {
onCloseCallback = callback onCloseCallback = callback
} }
override fun setOnAddonSubtitlesFetchCallback(callback: () -> Unit) {
onAddonSubtitlesFetchCallback = callback
}
override fun pushAddonSubtitles(subtitles: List<AddonSubtitle>, isLoading: Boolean) {
bridge.nuvio_player_set_addon_subtitles_loading(playerPtr, isLoading)
if (!isLoading) {
bridge.nuvio_player_clear_addon_subtitles(playerPtr)
subtitles.forEach { addon ->
bridge.nuvio_player_add_addon_subtitle(
playerPtr, addon.id, addon.url, addon.language, addon.display,
)
}
}
}
override fun setOnSourcesRequestedCallback(callback: () -> Unit) {
onSourcesRequestedCallback = callback
}
override fun setOnSourceStreamSelectedCallback(callback: (String) -> Unit) {
onSourceStreamSelectedCallback = callback
}
override fun setOnSourceFilterChangedCallback(callback: (String?) -> Unit) {
onSourceFilterChangedCallback = callback
}
override fun setOnSourceReloadCallback(callback: () -> Unit) {
onSourceReloadCallback = callback
}
override fun setOnEpisodesRequestedCallback(callback: () -> Unit) {
onEpisodesRequestedCallback = callback
}
override fun setOnEpisodeSelectedCallback(callback: (String) -> Unit) {
onEpisodeSelectedCallback = callback
}
override fun setOnEpisodeStreamSelectedCallback(callback: (String) -> Unit) {
onEpisodeStreamSelectedCallback = callback
}
override fun setOnEpisodeFilterChangedCallback(callback: (String?) -> Unit) {
onEpisodeFilterChangedCallback = callback
}
override fun setOnEpisodeReloadCallback(callback: () -> Unit) {
onEpisodeReloadCallback = callback
}
override fun setOnEpisodeBackCallback(callback: () -> Unit) {
onEpisodeBackCallback = callback
}
override fun pushSourceData(
streams: List<StreamItem>,
groups: List<AddonStreamGroup>,
loading: Boolean,
selectedFilter: String?,
currentStreamUrl: String?,
) {
bridge.nuvio_player_set_sources_loading(playerPtr, loading)
bridge.nuvio_player_set_source_selected_filter(playerPtr, selectedFilter)
bridge.nuvio_player_clear_source_addon_groups(playerPtr)
groups.forEach { g ->
bridge.nuvio_player_add_source_addon_group(
playerPtr, g.addonId, g.addonName, g.addonId, g.isLoading, g.error != null,
)
}
bridge.nuvio_player_clear_source_streams(playerPtr)
streams.forEach { s ->
bridge.nuvio_player_add_source_stream(
playerPtr, s.addonId + "_" + (s.url ?: s.infoHash ?: ""),
s.streamLabel, s.streamSubtitle, s.addonName, s.addonId,
s.directPlaybackUrl ?: "", s.directPlaybackUrl == currentStreamUrl,
)
}
}
override fun pushEpisodes(episodes: List<MetaVideo>) {
bridge.nuvio_player_clear_episodes(playerPtr)
episodes.forEach { ep ->
bridge.nuvio_player_add_episode(
playerPtr, ep.id, ep.title, ep.overview, ep.thumbnail,
ep.season ?: 0, ep.episode ?: 0,
)
}
}
override fun pushEpisodeStreamsData(
streams: List<StreamItem>,
groups: List<AddonStreamGroup>,
loading: Boolean,
selectedFilter: String?,
currentStreamUrl: String?,
) {
bridge.nuvio_player_set_episode_streams_loading(playerPtr, loading)
bridge.nuvio_player_set_episode_selected_filter(playerPtr, selectedFilter)
bridge.nuvio_player_clear_episode_addon_groups(playerPtr)
groups.forEach { g ->
bridge.nuvio_player_add_episode_addon_group(
playerPtr, g.addonId, g.addonName, g.addonId, g.isLoading, g.error != null,
)
}
bridge.nuvio_player_clear_episode_streams(playerPtr)
streams.forEach { s ->
bridge.nuvio_player_add_episode_stream(
playerPtr, s.addonId + "_" + (s.url ?: s.infoHash ?: ""),
s.streamLabel, s.streamSubtitle, s.addonName, s.addonId,
s.directPlaybackUrl ?: "", s.directPlaybackUrl == currentStreamUrl,
)
}
}
override fun showEpisodeStreamsView(season: Int?, episode: Int?, title: String?) {
bridge.nuvio_player_show_episode_streams(playerPtr, season ?: 0, episode ?: 0, title)
}
override fun switchSource(url: String, audioUrl: String?, headersJson: String?) {
bridge.nuvio_player_load_file(playerPtr, url, audioUrl, headersJson)
}
} }
} }
@ -225,6 +369,54 @@ actual fun PlatformPlayerSurface(
onSnapshot(snapshot) onSnapshot(snapshot)
val error = bridge.nuvio_player_get_error(playerPtr) val error = bridge.nuvio_player_get_error(playerPtr)
onError(error) onError(error)
if (bridge.nuvio_player_is_addon_subtitles_fetch_requested(playerPtr)) {
onAddonSubtitlesFetchCallback?.invoke()
}
if (bridge.nuvio_player_pop_subtitle_style_changed(playerPtr)) {
val colorIndex = bridge.nuvio_player_get_subtitle_style_color_index(playerPtr)
.coerceIn(0, SubtitleColorSwatches.lastIndex)
val style = SubtitleStyleState(
textColor = SubtitleColorSwatches[colorIndex],
outlineEnabled = bridge.nuvio_player_get_subtitle_style_outline_enabled(playerPtr),
fontSizeSp = bridge.nuvio_player_get_subtitle_style_font_size(playerPtr),
bottomOffset = bridge.nuvio_player_get_subtitle_style_bottom_offset(playerPtr),
)
PlayerSettingsRepository.setSubtitleStyle(style)
}
if (bridge.nuvio_player_pop_next_episode_pressed(playerPtr)) {
}
if (bridge.nuvio_player_pop_sources_open_requested(playerPtr)) {
onSourcesRequestedCallback?.invoke()
}
if (bridge.nuvio_player_pop_episodes_open_requested(playerPtr)) {
onEpisodesRequestedCallback?.invoke()
}
bridge.nuvio_player_pop_source_stream_selected(playerPtr)?.let { url ->
onSourceStreamSelectedCallback?.invoke(url)
}
if (bridge.nuvio_player_pop_source_filter_changed(playerPtr)) {
val filterValue = bridge.nuvio_player_get_source_filter_value(playerPtr)
onSourceFilterChangedCallback?.invoke(filterValue)
}
if (bridge.nuvio_player_pop_source_reload(playerPtr)) {
onSourceReloadCallback?.invoke()
}
bridge.nuvio_player_pop_episode_selected(playerPtr)?.let { episodeId ->
onEpisodeSelectedCallback?.invoke(episodeId)
}
bridge.nuvio_player_pop_episode_stream_selected(playerPtr)?.let { url ->
onEpisodeStreamSelectedCallback?.invoke(url)
}
if (bridge.nuvio_player_pop_episode_filter_changed(playerPtr)) {
val filterValue = bridge.nuvio_player_get_episode_filter_value(playerPtr)
onEpisodeFilterChangedCallback?.invoke(filterValue)
}
if (bridge.nuvio_player_pop_episode_reload(playerPtr)) {
onEpisodeReloadCallback?.invoke()
}
if (bridge.nuvio_player_pop_episode_back(playerPtr)) {
onEpisodeBackCallback?.invoke()
}
} }
} }
@ -290,10 +482,6 @@ internal actual object PlayerSettingsStorage {
secondaryPreferredAudioLanguageKey, secondaryPreferredAudioLanguageKey,
preferredSubtitleLanguageKey, preferredSubtitleLanguageKey,
secondaryPreferredSubtitleLanguageKey, secondaryPreferredSubtitleLanguageKey,
subtitleTextColorKey,
subtitleOutlineEnabledKey,
subtitleFontSizeSpKey,
subtitleBottomOffsetKey,
streamReuseLastLinkEnabledKey, streamReuseLastLinkEnabledKey,
streamReuseLastLinkCacheHoursKey, streamReuseLastLinkCacheHoursKey,
decoderPriorityKey, decoderPriorityKey,
@ -524,10 +712,6 @@ internal actual object PlayerSettingsStorage {
loadSecondaryPreferredAudioLanguage()?.let { put(secondaryPreferredAudioLanguageKey, encodeSyncString(it)) } loadSecondaryPreferredAudioLanguage()?.let { put(secondaryPreferredAudioLanguageKey, encodeSyncString(it)) }
loadPreferredSubtitleLanguage()?.let { put(preferredSubtitleLanguageKey, encodeSyncString(it)) } loadPreferredSubtitleLanguage()?.let { put(preferredSubtitleLanguageKey, encodeSyncString(it)) }
loadSecondaryPreferredSubtitleLanguage()?.let { put(secondaryPreferredSubtitleLanguageKey, encodeSyncString(it)) } loadSecondaryPreferredSubtitleLanguage()?.let { put(secondaryPreferredSubtitleLanguageKey, encodeSyncString(it)) }
loadSubtitleTextColor()?.let { put(subtitleTextColorKey, encodeSyncString(it)) }
loadSubtitleOutlineEnabled()?.let { put(subtitleOutlineEnabledKey, encodeSyncBoolean(it)) }
loadSubtitleFontSizeSp()?.let { put(subtitleFontSizeSpKey, encodeSyncInt(it)) }
loadSubtitleBottomOffset()?.let { put(subtitleBottomOffsetKey, encodeSyncInt(it)) }
loadStreamReuseLastLinkEnabled()?.let { put(streamReuseLastLinkEnabledKey, encodeSyncBoolean(it)) } loadStreamReuseLastLinkEnabled()?.let { put(streamReuseLastLinkEnabledKey, encodeSyncBoolean(it)) }
loadStreamReuseLastLinkCacheHours()?.let { put(streamReuseLastLinkCacheHoursKey, encodeSyncInt(it)) } loadStreamReuseLastLinkCacheHours()?.let { put(streamReuseLastLinkCacheHoursKey, encodeSyncInt(it)) }
loadDecoderPriority()?.let { put(decoderPriorityKey, encodeSyncInt(it)) } loadDecoderPriority()?.let { put(decoderPriorityKey, encodeSyncInt(it)) }
@ -562,10 +746,6 @@ internal actual object PlayerSettingsStorage {
payload.decodeSyncString(secondaryPreferredAudioLanguageKey)?.let(::saveSecondaryPreferredAudioLanguage) payload.decodeSyncString(secondaryPreferredAudioLanguageKey)?.let(::saveSecondaryPreferredAudioLanguage)
payload.decodeSyncString(preferredSubtitleLanguageKey)?.let(::savePreferredSubtitleLanguage) payload.decodeSyncString(preferredSubtitleLanguageKey)?.let(::savePreferredSubtitleLanguage)
payload.decodeSyncString(secondaryPreferredSubtitleLanguageKey)?.let(::saveSecondaryPreferredSubtitleLanguage) payload.decodeSyncString(secondaryPreferredSubtitleLanguageKey)?.let(::saveSecondaryPreferredSubtitleLanguage)
payload.decodeSyncString(subtitleTextColorKey)?.let(::saveSubtitleTextColor)
payload.decodeSyncBoolean(subtitleOutlineEnabledKey)?.let(::saveSubtitleOutlineEnabled)
payload.decodeSyncInt(subtitleFontSizeSpKey)?.let(::saveSubtitleFontSizeSp)
payload.decodeSyncInt(subtitleBottomOffsetKey)?.let(::saveSubtitleBottomOffset)
payload.decodeSyncBoolean(streamReuseLastLinkEnabledKey)?.let(::saveStreamReuseLastLinkEnabled) payload.decodeSyncBoolean(streamReuseLastLinkEnabledKey)?.let(::saveStreamReuseLastLinkEnabled)
payload.decodeSyncInt(streamReuseLastLinkCacheHoursKey)?.let(::saveStreamReuseLastLinkCacheHours) payload.decodeSyncInt(streamReuseLastLinkCacheHoursKey)?.let(::saveStreamReuseLastLinkCacheHours)
payload.decodeSyncInt(decoderPriorityKey)?.let(::saveDecoderPriority) payload.decodeSyncInt(decoderPriorityKey)?.let(::saveDecoderPriority)