mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-17 15:32:01 +00:00
feat(macos): player functionality with new callbacks
This commit is contained in:
parent
859027f3fd
commit
da1b83c3b7
5 changed files with 407 additions and 14 deletions
2
MPVKit
2
MPVKit
|
|
@ -1 +1 @@
|
|||
Subproject commit 61e0e8683f0558fe3ff2299b1fbfd97799a2474d
|
||||
Subproject commit a633ca46a3d9713e6edc885ef0e17448054997f7
|
||||
|
|
@ -28,6 +28,7 @@ interface PlayerEngineController {
|
|||
artwork: String? = null,
|
||||
logo: String? = null,
|
||||
) {}
|
||||
fun setPlayerFlags(hasVideoId: Boolean, isSeries: Boolean) {}
|
||||
fun showSkipButton(type: String, endTimeMs: Long) {}
|
||||
fun hideSkipButton() {}
|
||||
fun showNextEpisode(
|
||||
|
|
@ -39,6 +40,35 @@ interface PlayerEngineController {
|
|||
) {}
|
||||
fun hideNextEpisode() {}
|
||||
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> {
|
||||
|
|
|
|||
|
|
@ -1023,6 +1023,30 @@ fun PlayerScreen(
|
|||
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) {
|
||||
if (!playbackSnapshot.isLoading && playerController != null) {
|
||||
refreshTracks()
|
||||
|
|
@ -1441,7 +1465,124 @@ fun PlayerScreen(
|
|||
artwork = backdropArtwork,
|
||||
logo = logo,
|
||||
)
|
||||
controller.setPlayerFlags(
|
||||
hasVideoId = activeVideoId != null,
|
||||
isSeries = parentMetaType == "series",
|
||||
)
|
||||
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 ->
|
||||
playbackSnapshot = snapshot
|
||||
|
|
|
|||
|
|
@ -52,6 +52,9 @@ internal interface DesktopMPVBridgeLib : Library {
|
|||
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(
|
||||
player: Pointer,
|
||||
url: String,
|
||||
|
|
@ -117,4 +120,43 @@ internal interface DesktopMPVBridgeLib : Library {
|
|||
|
||||
fun nuvio_player_is_closed(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?)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ import com.nuvio.app.core.sync.encodeSyncInt
|
|||
import com.nuvio.app.core.sync.encodeSyncString
|
||||
import com.nuvio.app.core.sync.encodeSyncStringSet
|
||||
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 java.util.Locale
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
@ -50,6 +53,17 @@ actual fun PlatformPlayerSurface(
|
|||
val bridge = remember { DesktopMPVBridgeLib.INSTANCE }
|
||||
val playerPtr = remember { bridge.nuvio_player_create() }
|
||||
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) {
|
||||
bridge.nuvio_player_show(playerPtr)
|
||||
|
|
@ -151,8 +165,9 @@ actual fun PlatformPlayerSurface(
|
|||
override fun applySubtitleStyle(style: SubtitleStyleState) {
|
||||
val colorHex = style.textColor.toMpvColorString()
|
||||
val outline = if (style.outlineEnabled) 2.0f else 0.0f
|
||||
val subPos = 100 - style.bottomOffset
|
||||
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) {
|
||||
bridge.nuvio_player_show_skip_button(playerPtr, type, endTimeMs)
|
||||
}
|
||||
|
|
@ -198,6 +218,130 @@ actual fun PlatformPlayerSurface(
|
|||
override fun setOnCloseCallback(callback: () -> Unit) {
|
||||
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)
|
||||
val error = bridge.nuvio_player_get_error(playerPtr)
|
||||
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,
|
||||
preferredSubtitleLanguageKey,
|
||||
secondaryPreferredSubtitleLanguageKey,
|
||||
subtitleTextColorKey,
|
||||
subtitleOutlineEnabledKey,
|
||||
subtitleFontSizeSpKey,
|
||||
subtitleBottomOffsetKey,
|
||||
streamReuseLastLinkEnabledKey,
|
||||
streamReuseLastLinkCacheHoursKey,
|
||||
decoderPriorityKey,
|
||||
|
|
@ -524,10 +712,6 @@ internal actual object PlayerSettingsStorage {
|
|||
loadSecondaryPreferredAudioLanguage()?.let { put(secondaryPreferredAudioLanguageKey, encodeSyncString(it)) }
|
||||
loadPreferredSubtitleLanguage()?.let { put(preferredSubtitleLanguageKey, 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)) }
|
||||
loadStreamReuseLastLinkCacheHours()?.let { put(streamReuseLastLinkCacheHoursKey, encodeSyncInt(it)) }
|
||||
loadDecoderPriority()?.let { put(decoderPriorityKey, encodeSyncInt(it)) }
|
||||
|
|
@ -562,10 +746,6 @@ internal actual object PlayerSettingsStorage {
|
|||
payload.decodeSyncString(secondaryPreferredAudioLanguageKey)?.let(::saveSecondaryPreferredAudioLanguage)
|
||||
payload.decodeSyncString(preferredSubtitleLanguageKey)?.let(::savePreferredSubtitleLanguage)
|
||||
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.decodeSyncInt(streamReuseLastLinkCacheHoursKey)?.let(::saveStreamReuseLastLinkCacheHours)
|
||||
payload.decodeSyncInt(decoderPriorityKey)?.let(::saveDecoderPriority)
|
||||
|
|
|
|||
Loading…
Reference in a new issue