Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ import io.github.kdroidfilter.composemediaplayer.SubtitleTrack
import io.github.kdroidfilter.composemediaplayer.VideoMetadata
import io.github.kdroidfilter.composemediaplayer.VideoPlayerError
import io.github.kdroidfilter.composemediaplayer.util.formatTime
import io.github.vinceglb.filekit.utils.toFile
import io.github.vinceglb.filekit.utils.toPath
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import java.awt.image.BufferedImage
import java.awt.image.DataBufferInt
import java.net.URI
import kotlin.math.abs
import kotlin.math.log10

Expand Down Expand Up @@ -218,21 +221,33 @@ class MacVideoPlayerState : PlatformVideoPlayerState {
}
}

// Check if this is a local file that doesn't exist
// This handles both URIs with a "file:" scheme and simple filenames without a scheme, with or without authority.
private fun checkExistsIfLocalFile(uri: String): Boolean {
val javaUri = try {
URI.create(uri)
} catch (e: IllegalArgumentException) {
macLogger.e(e) { "URI object is malformed: $uri" }
return false
}
return if (javaUri.scheme == "file" || javaUri.scheme == null) {
val file = javaUri.path?.toPath()?.toFile()
file?.exists() == true
} else {
true
}
}

override fun openUri(uri: String, initializeplayerState: InitialPlayerState) {
macLogger.d { "openUri() - Opening URI: $uri, initializeplayerState: $initializeplayerState" }

lastUri = uri

// Check if this is a local file that doesn't exist
// This handles both URIs with file:// scheme and simple filenames without a scheme
if (uri.startsWith("file://") || !uri.contains("://") || !uri.matches("^[a-zA-Z]+://.*".toRegex())) {
val filePath = uri.replace("file://", "")
val file = java.io.File(filePath)
if (!file.exists()) {
macLogger.e { "File does not exist: $filePath" }
setPlayerError(VideoPlayerError.SourceError("File not found: $filePath"))
return
}
if (!checkExistsIfLocalFile(uri)) {
macLogger.e { "File does not exist: $uri" }
setPlayerError(VideoPlayerError.SourceError("File not found: $uri"))
return
}

// Update UI state first
Expand Down Expand Up @@ -352,15 +367,11 @@ class MacVideoPlayerState : PlatformVideoPlayerState {

// Check if file exists (for local files)
// This handles both URIs with file:// scheme and simple filenames without a scheme
if (uri.startsWith("file://") || !uri.contains("://") || !uri.matches("^[a-zA-Z]+://.*".toRegex())) {
val filePath = uri.replace("file://", "")
val file = java.io.File(filePath)
if (!file.exists()) {
macLogger.e { "File does not exist: $filePath" }
// Use setPlayerError to ensure the error is set synchronously
setPlayerError(VideoPlayerError.SourceError("File not found: $filePath"))
return false
}
if (!checkExistsIfLocalFile(uri)) {
macLogger.e { "File does not exist: $uri" }
// Use setPlayerError to ensure the error is set synchronously
setPlayerError(VideoPlayerError.SourceError("File not found: $uri"))
return false
}

return try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package io.github.kdroidfilter.composemediaplayer.mac

import io.github.kdroidfilter.composemediaplayer.PlatformVideoPlayerState
import io.github.kdroidfilter.composemediaplayer.VideoPlayerError
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
Expand Down Expand Up @@ -168,4 +166,82 @@ class MacVideoPlayerStateTest {
// Clean up
playerState.dispose()
}

private fun testOpenLocalFile(file: String) {
// Skip test if not running on Mac
if (!Platform.isMac()) {
println("Skipping Mac-specific test on non-Mac platform")
return
}

val playerState = MacVideoPlayerState()

// Initially there should be no error
assertNull(playerState.error)

// Test opening a non-existent file (should cause an error)
runBlocking {
playerState.openUri(file)
delay(500) // Give some time for the error to be set
}

// There should be no error
assertNull(playerState.error)

// Clean up
playerState.dispose()
}

@Test
fun testOpenLocalFile() {
val path = assertNotNull(javaClass.classLoader.getResource("existing_file.mp4")).toURI().path
testOpenLocalFile(path)
}

@Test
fun testOpenLocalFileWithScheme() {
val path = assertNotNull(javaClass.classLoader.getResource("existing_file.mp4")).toURI().path
testOpenLocalFile("file:$path")
}

@Test
fun testOpenLocalFileWithSchemeWithAuthority() {
val path = assertNotNull(javaClass.classLoader.getResource("existing_file.mp4")).toURI().path
testOpenLocalFile("file://$path")
}

private fun testMalformedUri(uri: String) {
// Skip test if not running on Mac
if (!Platform.isMac()) {
println("Skipping Mac-specific test on non-Mac platform")
return
}

val playerState = MacVideoPlayerState()

// Initially there should be no error
assertNull(playerState.error)

// Test opening a non-existent file (should cause an error)
runBlocking {
playerState.openUri(uri)
delay(500) // Give some time for the error to be set
}

// There should be an error now
assertNotNull(playerState.error)

// Test clearing the error
playerState.clearError()
assertNull(playerState.error)

// Clean up
playerState.dispose()
}

@Test
fun testMalformedUri() {
val path = assertNotNull(javaClass.classLoader.getResource("existing_file.mp4")).toURI().path
testMalformedUri("file:${path.removePrefix("/")}")
}
}
Empty file.
Loading