mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-08-16 12:24:40 +00:00
feat: Refactor player control icons to use AppIconResource and add error handling in player bridge
This commit is contained in:
parent
aac7fc9534
commit
0c4b81599d
14 changed files with 203 additions and 23 deletions
|
|
@ -0,0 +1,19 @@
|
|||
package com.nuvio.app.core.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import com.nuvio.app.R
|
||||
|
||||
@Composable
|
||||
actual fun appIconPainter(icon: AppIconResource): Painter =
|
||||
painterResource(
|
||||
id = when (icon) {
|
||||
AppIconResource.PlayerPlay -> R.drawable.ic_player_play
|
||||
AppIconResource.PlayerPause -> R.drawable.ic_player_pause
|
||||
AppIconResource.PlayerAspectRatio -> R.drawable.ic_player_aspect_ratio
|
||||
AppIconResource.PlayerSubtitles -> R.drawable.ic_player_subtitles
|
||||
AppIconResource.PlayerAudioFilled -> R.drawable.ic_player_audio_filled
|
||||
AppIconResource.LibraryAddPlus -> R.drawable.library_add_plus
|
||||
}
|
||||
)
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19,3C20.5976809,3 21.9036609,4.24891996 21.9949073,5.82372721L22,6L22,18C22,19.5976809 20.75108,20.9036609 19.1762728,20.9949073L19,21L5,21C3.40231912,21 2.09633912,19.75108 2.00509269,18.1762728L2,18L2,6C2,4.40231912 3.24891996,3.09633912 4.82372721,3.00509269L5,3L19,3ZM19,5L5,5C4.48716416,5 4.06449284,5.38604019 4.00672773,5.88337887L4,6L4,18C4,18.5128358 4.38604019,18.9355072 4.88337887,18.9932723L5,19L19,19C19.5128358,19 19.9355072,18.6139598 19.9932723,18.1166211L20,18L20,6C20,5.48716416 19.6139598,5.06449284 19.1166211,5.00672773L19,5ZM17,12C17.5128358,12 17.9355072,12.3860402 17.9932723,12.8833789L18,13L18,16C18,16.5128358 17.6139598,16.9355072 17.1166211,16.9932723L17,17L14,17C13.4477153,17 13,16.5522847 13,16C13,15.4871642 13.3860402,15.0644928 13.8833789,15.0067277L14,15L16,15L16,13C16,12.4871642 16.3860402,12.0644928 16.8833789,12.0067277L17,12ZM10,7C10.5522847,7 11,7.44771525 11,8C11,8.51283584 10.6139598,8.93550716 10.1166211,8.99327227L10,9L8,9L8,11C8,11.5128358 7.61395981,11.9355072 7.11662113,11.9932723L7,12C6.48716416,12 6.06449284,11.6139598 6.00672773,11.1166211L6,11L6,8C6,7.48716416 6.38604019,7.06449284 6.88337887,7.00672773L7,7L10,7Z" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF1C274C"
|
||||
android:pathData="M12,6.25C11.3096,6.25 10.75,6.80964 10.75,7.5C10.75,8.19036 11.3096,8.75 12,8.75C12.6904,8.75 13.25,8.19036 13.25,7.5C13.25,6.80964 12.6904,6.25 12,6.25Z" />
|
||||
<path
|
||||
android:fillColor="#FF1C274C"
|
||||
android:pathData="M9.75,15.5C9.75,14.2574 10.7574,13.25 12,13.25C13.2426,13.25 14.25,14.2574 14.25,15.5C14.25,16.7426 13.2426,17.75 12,17.75C10.7574,17.75 9.75,16.7426 9.75,15.5Z" />
|
||||
<path
|
||||
android:fillColor="#FF1C274C"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M4,10C4,6.22876 4,4.34315 5.17157,3.17157C6.34315,2 8.22876,2 12,2C15.7712,2 17.6569,2 18.8284,3.17157C20,4.34315 20,6.22876 20,10V14C20,17.7712 20,19.6569 18.8284,20.8284C17.6569,22 15.7712,22 12,22C8.22876,22 6.34315,22 5.17157,20.8284C4,19.6569 4,17.7712 4,14V10ZM9.25,7.5C9.25,5.98122 10.4812,4.75 12,4.75C13.5188,4.75 14.75,5.98122 14.75,7.5C14.75,9.01878 13.5188,10.25 12,10.25C10.4812,10.25 9.25,9.01878 9.25,7.5ZM12,11.75C9.92893,11.75 8.25,13.4289 8.25,15.5C8.25,17.5711 9.92893,19.25 12,19.25C14.0711,19.25 15.75,17.5711 15.75,15.5C15.75,13.4289 14.0711,11.75 12,11.75Z" />
|
||||
</vector>
|
||||
13
composeApp/src/androidMain/res/drawable/ic_player_pause.xml
Normal file
13
composeApp/src/androidMain/res/drawable/ic_player_pause.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF1C274C"
|
||||
android:pathData="M2,6C2,4.11438 2,3.17157 2.58579,2.58579C3.17157,2 4.11438,2 6,2C7.88562,2 8.82843,2 9.41421,2.58579C10,3.17157 10,4.11438 10,6V18C10,19.8856 10,20.8284 9.41421,21.4142C8.82843,22 7.88562,22 6,22C4.11438,22 3.17157,22 2.58579,21.4142C2,20.8284 2,19.8856 2,18V6Z" />
|
||||
<path
|
||||
android:fillColor="#FF1C274C"
|
||||
android:pathData="M14,6C14,4.11438 14,3.17157 14.5858,2.58579C15.1716,2 16.1144,2 18,2C19.8856,2 20.8284,2 21.4142,2.58579C22,3.17157 22,4.11438 22,6V18C22,19.8856 22,20.8284 21.4142,21.4142C20.8284,22 19.8856,22 18,22C16.1144,22 15.1716,22 14.5858,21.4142C14,20.8284 14,19.8856 14,18V6Z" />
|
||||
</vector>
|
||||
10
composeApp/src/androidMain/res/drawable/ic_player_play.xml
Normal file
10
composeApp/src/androidMain/res/drawable/ic_player_play.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF1C274C"
|
||||
android:pathData="M21.4086,9.35258C23.5305,10.5065 23.5305,13.4935 21.4086,14.6474L8.59662,21.6145C6.53435,22.736 4,21.2763 4,18.9671L4,5.0329C4,2.72368 6.53435,1.26402 8.59661,2.38548L21.4086,9.35258Z" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M1,12C1,5 2.5,4 12,4C21.5,4 23,5 23,12C23,19 21.5,20 12,20C2.5,20 1,19 1,12ZM5.25,14C5.25,15.5 6,16 7.75,16C9.5,16 10.25,15.5 10.25,14L9.97861679,14C9.97861671,15.25 8.97905547,16 7.75,16C6.52094453,16 5.52138329,15.25 5.52138321,14L5.52138321,10C5.5,8.75 6.5,8 7.75,8C9,8 10,8.75 9.97861679,10L10.25,10C10.25,8.75 9.2286998,8 7.75,8C6.2713002,8 5.25,8.75 5.25,10L5.25,14ZM13.25,14C13.25,15.5 14,16 15.75,16C17.5,16 18.25,15.5 18.25,14L17.9786168,14C17.9786167,15.25 16.9790555,16 15.75,16C14.5209445,16 13.5213833,15.25 13.5213832,14L13.5213832,10C13.5,8.75 14.5,8 15.75,8C17,8 18,8.75 17.9786168,10L18.25,10C18.25,8.75 17.2286998,8 15.75,8C14.2713002,8 13.25,8.75 13.25,10L13.25,14Z"
|
||||
android:strokeColor="#FF000000"
|
||||
android:strokeWidth="2" />
|
||||
</vector>
|
||||
14
composeApp/src/androidMain/res/drawable/library_add_plus.xml
Normal file
14
composeApp/src/androidMain/res/drawable/library_add_plus.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M4,12H20M12,4V20"
|
||||
android:strokeColor="#FF000000"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.nuvio.app.core.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
|
||||
enum class AppIconResource {
|
||||
PlayerPlay,
|
||||
PlayerPause,
|
||||
PlayerAspectRatio,
|
||||
PlayerSubtitles,
|
||||
PlayerAudioFilled,
|
||||
LibraryAddPlus,
|
||||
}
|
||||
|
||||
@Composable
|
||||
expect fun appIconPainter(icon: AppIconResource): Painter
|
||||
|
|
@ -21,10 +21,8 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import nuvio.composeapp.generated.resources.Res
|
||||
import nuvio.composeapp.generated.resources.ic_player_play
|
||||
import nuvio.composeapp.generated.resources.library_add_plus
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import com.nuvio.app.core.ui.AppIconResource
|
||||
import com.nuvio.app.core.ui.appIconPainter
|
||||
|
||||
@Composable
|
||||
fun DetailActionButtons(
|
||||
|
|
@ -35,8 +33,8 @@ fun DetailActionButtons(
|
|||
onPlayClick: () -> Unit = {},
|
||||
onSaveClick: () -> Unit = {},
|
||||
) {
|
||||
val playPainter = painterResource(Res.drawable.ic_player_play)
|
||||
val libraryAddPainter = painterResource(Res.drawable.library_add_plus)
|
||||
val playPainter = appIconPainter(AppIconResource.PlayerPlay)
|
||||
val libraryAddPainter = appIconPainter(AppIconResource.LibraryAddPlus)
|
||||
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
|
|
|
|||
|
|
@ -42,15 +42,10 @@ import androidx.compose.ui.text.font.FontStyle
|
|||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.nuvio.app.core.ui.AppIconResource
|
||||
import com.nuvio.app.core.ui.NuvioBackButton
|
||||
import com.nuvio.app.core.ui.appIconPainter
|
||||
import com.nuvio.app.core.ui.nuvioTypeScale
|
||||
import nuvio.composeapp.generated.resources.Res
|
||||
import nuvio.composeapp.generated.resources.ic_player_aspect_ratio
|
||||
import nuvio.composeapp.generated.resources.ic_player_audio_filled
|
||||
import nuvio.composeapp.generated.resources.ic_player_pause
|
||||
import nuvio.composeapp.generated.resources.ic_player_play
|
||||
import nuvio.composeapp.generated.resources.ic_player_subtitles
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
|
||||
@Composable
|
||||
internal fun PlayerControlsShell(
|
||||
|
|
@ -321,8 +316,8 @@ private fun PlayPauseControlButton(
|
|||
metrics: PlayerLayoutMetrics,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
val playPausePainter = painterResource(
|
||||
if (isPlaying) Res.drawable.ic_player_pause else Res.drawable.ic_player_play,
|
||||
val playPausePainter = appIconPainter(
|
||||
if (isPlaying) AppIconResource.PlayerPause else AppIconResource.PlayerPlay,
|
||||
)
|
||||
|
||||
Box(
|
||||
|
|
@ -364,9 +359,9 @@ private fun ProgressControls(
|
|||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val durationMs = playbackSnapshot.durationMs.coerceAtLeast(1L)
|
||||
val aspectRatioPainter = painterResource(Res.drawable.ic_player_aspect_ratio)
|
||||
val subtitlesPainter = painterResource(Res.drawable.ic_player_subtitles)
|
||||
val audioPainter = painterResource(Res.drawable.ic_player_audio_filled)
|
||||
val aspectRatioPainter = appIconPainter(AppIconResource.PlayerAspectRatio)
|
||||
val subtitlesPainter = appIconPainter(AppIconResource.PlayerSubtitles)
|
||||
val audioPainter = appIconPainter(AppIconResource.PlayerAudioFilled)
|
||||
|
||||
Column(modifier = modifier) {
|
||||
Slider(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
package com.nuvio.app.core.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import nuvio.composeapp.generated.resources.Res
|
||||
import nuvio.composeapp.generated.resources.ic_player_aspect_ratio
|
||||
import nuvio.composeapp.generated.resources.ic_player_audio_filled
|
||||
import nuvio.composeapp.generated.resources.ic_player_pause
|
||||
import nuvio.composeapp.generated.resources.ic_player_play
|
||||
import nuvio.composeapp.generated.resources.ic_player_subtitles
|
||||
import nuvio.composeapp.generated.resources.library_add_plus
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
|
||||
@Composable
|
||||
actual fun appIconPainter(icon: AppIconResource): Painter =
|
||||
painterResource(
|
||||
when (icon) {
|
||||
AppIconResource.PlayerPlay -> Res.drawable.ic_player_play
|
||||
AppIconResource.PlayerPause -> Res.drawable.ic_player_pause
|
||||
AppIconResource.PlayerAspectRatio -> Res.drawable.ic_player_aspect_ratio
|
||||
AppIconResource.PlayerSubtitles -> Res.drawable.ic_player_subtitles
|
||||
AppIconResource.PlayerAudioFilled -> Res.drawable.ic_player_audio_filled
|
||||
AppIconResource.LibraryAddPlus -> Res.drawable.library_add_plus
|
||||
}
|
||||
)
|
||||
|
|
@ -40,6 +40,7 @@ interface NuvioPlayerBridge {
|
|||
fun getPositionMs(): Long
|
||||
fun getBufferedMs(): Long
|
||||
fun getPlaybackSpeed(): Float
|
||||
fun getErrorMessage(): String
|
||||
fun destroy()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@ actual fun PlatformPlayerSurface(
|
|||
|
||||
// Polling for snapshots
|
||||
LaunchedEffect(bridge) {
|
||||
var lastReportedError: String? = null
|
||||
while (isActive) {
|
||||
val snapshot = PlayerPlaybackSnapshot(
|
||||
isLoading = bridge.getIsLoading(),
|
||||
|
|
@ -185,6 +186,11 @@ actual fun PlatformPlayerSurface(
|
|||
playbackSpeed = bridge.getPlaybackSpeed(),
|
||||
)
|
||||
latestOnSnapshot.value(snapshot)
|
||||
val errorMessage = bridge.getErrorMessage().ifBlank { null }
|
||||
if (errorMessage != lastReportedError) {
|
||||
lastReportedError = errorMessage
|
||||
latestOnError.value(errorMessage)
|
||||
}
|
||||
delay(250L)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ final class MPVPlayerBridgeImpl: NSObject, NuvioPlayerBridge {
|
|||
func getPositionMs() -> Int64 { return playerVC?.positionMs ?? 0 }
|
||||
func getBufferedMs() -> Int64 { return playerVC?.bufferedMs ?? 0 }
|
||||
func getPlaybackSpeed() -> Float { playerVC?.currentSpeed ?? 1.0 }
|
||||
func getErrorMessage() -> String { playerVC?.currentErrorMessage ?? "" }
|
||||
|
||||
func destroy() {
|
||||
playerVC?.destroyPlayer()
|
||||
|
|
@ -106,9 +107,11 @@ struct TrackInfo {
|
|||
|
||||
final class MPVPlayerViewController: UIViewController {
|
||||
|
||||
private let errorStateLock = NSLock()
|
||||
private var metalLayer = MetalLayer()
|
||||
private var mpv: OpaquePointer?
|
||||
private lazy var eventQueue = DispatchQueue(label: "mpv-events", qos: .userInitiated)
|
||||
private var recentPlaybackLogs: [String] = []
|
||||
|
||||
// Cached track lists
|
||||
var audioTracks: [TrackInfo] = []
|
||||
|
|
@ -122,6 +125,12 @@ final class MPVPlayerViewController: UIViewController {
|
|||
var positionMs: Int64 = 0
|
||||
var bufferedMs: Int64 = 0
|
||||
var currentSpeed: Float = 1.0
|
||||
var currentErrorMessage: String {
|
||||
errorStateLock.lock()
|
||||
defer { errorStateLock.unlock() }
|
||||
return _currentErrorMessage ?? ""
|
||||
}
|
||||
private var _currentErrorMessage: String?
|
||||
|
||||
// MARK: - Lifecycle
|
||||
|
||||
|
|
@ -153,11 +162,7 @@ final class MPVPlayerViewController: UIViewController {
|
|||
return
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
checkError(mpv_request_log_messages(mpv, "warn"))
|
||||
#else
|
||||
checkError(mpv_request_log_messages(mpv, "no"))
|
||||
#endif
|
||||
|
||||
checkError(mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &metalLayer))
|
||||
checkError(mpv_set_option_string(mpv, "vo", "gpu-next"))
|
||||
|
|
@ -209,6 +214,7 @@ final class MPVPlayerViewController: UIViewController {
|
|||
|
||||
func loadFile(_ urlString: String) {
|
||||
guard mpv != nil else { return }
|
||||
clearPlaybackError()
|
||||
isPlayerLoading = true
|
||||
isPlayerEnded = false
|
||||
command("loadfile", args: [urlString, "replace"])
|
||||
|
|
@ -239,6 +245,7 @@ final class MPVPlayerViewController: UIViewController {
|
|||
func retryPlayback() {
|
||||
guard mpv != nil else { return }
|
||||
if let path = getString("path") {
|
||||
clearPlaybackError()
|
||||
let pos = getDouble("time-pos")
|
||||
command("loadfile", args: [path, "replace"])
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
||||
|
|
@ -325,6 +332,7 @@ final class MPVPlayerViewController: UIViewController {
|
|||
|
||||
func destroyPlayer() {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
clearPlaybackError()
|
||||
guard let ctx = mpv else { return }
|
||||
mpv = nil // nil first so event loop stops reading
|
||||
mpv_terminate_destroy(ctx)
|
||||
|
|
@ -388,6 +396,38 @@ final class MPVPlayerViewController: UIViewController {
|
|||
subtitleTracks = subs
|
||||
}
|
||||
|
||||
private func clearPlaybackError() {
|
||||
errorStateLock.lock()
|
||||
recentPlaybackLogs.removeAll(keepingCapacity: true)
|
||||
_currentErrorMessage = nil
|
||||
errorStateLock.unlock()
|
||||
}
|
||||
|
||||
private func appendPlaybackLog(prefix: String, level: String, text: String) {
|
||||
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
guard !trimmed.isEmpty else { return }
|
||||
guard level == "warn" || level == "error" || level == "fatal" else { return }
|
||||
|
||||
let formatted = "[\(prefix)] \(trimmed)"
|
||||
errorStateLock.lock()
|
||||
recentPlaybackLogs.append(formatted)
|
||||
if recentPlaybackLogs.count > 4 {
|
||||
recentPlaybackLogs.removeFirst(recentPlaybackLogs.count - 4)
|
||||
}
|
||||
errorStateLock.unlock()
|
||||
}
|
||||
|
||||
private func setPlaybackError(_ fallback: String) {
|
||||
let trimmedFallback = fallback.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
errorStateLock.lock()
|
||||
var parts = recentPlaybackLogs.suffix(3)
|
||||
if !trimmedFallback.isEmpty && !parts.contains(trimmedFallback) {
|
||||
parts.append(trimmedFallback)
|
||||
}
|
||||
_currentErrorMessage = parts.isEmpty ? "Unable to play this stream." : parts.joined(separator: "\n")
|
||||
errorStateLock.unlock()
|
||||
}
|
||||
|
||||
// MARK: - Event Loop
|
||||
|
||||
private func readEvents() {
|
||||
|
|
@ -404,6 +444,7 @@ final class MPVPlayerViewController: UIViewController {
|
|||
DispatchQueue.main.async { self.updateState() }
|
||||
case MPV_EVENT_FILE_LOADED:
|
||||
DispatchQueue.main.async {
|
||||
self.clearPlaybackError()
|
||||
self.isPlayerLoading = false
|
||||
self.updateState()
|
||||
}
|
||||
|
|
@ -411,7 +452,9 @@ final class MPVPlayerViewController: UIViewController {
|
|||
if let data = eventPtr.pointee.data {
|
||||
let endFile = UnsafePointer<mpv_event_end_file>(OpaquePointer(data)).pointee
|
||||
if endFile.reason == MPV_END_FILE_REASON_ERROR {
|
||||
print("[MPV] End file error: \(String(cString: mpv_error_string(endFile.error)))")
|
||||
let errorText = String(cString: mpv_error_string(endFile.error))
|
||||
self.setPlaybackError("[mpv] \(errorText)")
|
||||
print("[MPV] End file error: \(errorText)")
|
||||
}
|
||||
}
|
||||
case MPV_EVENT_SHUTDOWN:
|
||||
|
|
@ -421,6 +464,7 @@ final class MPVPlayerViewController: UIViewController {
|
|||
let prefix = String(cString: msg.pointee.prefix!)
|
||||
let level = String(cString: msg.pointee.level!)
|
||||
let text = String(cString: msg.pointee.text!)
|
||||
self.appendPlaybackLog(prefix: prefix, level: level, text: text)
|
||||
print("[MPV][\(prefix)] \(level): \(text)", terminator: "")
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
Loading…
Reference in a new issue