diff --git a/app/src/main/java/com/lostf1sh/pixelplayeross/data/jellyfin/model/JellyfinCredentials.kt b/app/src/main/java/com/lostf1sh/pixelplayeross/data/jellyfin/model/JellyfinCredentials.kt index 850fd43..85a0e77 100644 --- a/app/src/main/java/com/lostf1sh/pixelplayeross/data/jellyfin/model/JellyfinCredentials.kt +++ b/app/src/main/java/com/lostf1sh/pixelplayeross/data/jellyfin/model/JellyfinCredentials.kt @@ -31,11 +31,13 @@ data class JellyfinCredentials( val normalizedHttpUrlOrNull: HttpUrl? get() { val trimmed = serverUrl.trim().trimEnd('/') - // Auto-prepend https:// if no scheme is provided - val withScheme = if (!trimmed.startsWith("http://", ignoreCase = true) && - !trimmed.startsWith("https://", ignoreCase = true) - ) { - "https://$trimmed" + val hasScheme = trimmed.startsWith("http://", ignoreCase = true) || + trimmed.startsWith("https://", ignoreCase = true) + + val withScheme = if (!hasScheme) { + val host = "http://$trimmed".toHttpUrlOrNull()?.host?.lowercase() + val scheme = if (host != null && isHttpAllowedHost(host)) "http" else "https" + "$scheme://$trimmed" } else { trimmed } diff --git a/app/src/main/java/com/lostf1sh/pixelplayeross/presentation/jellyfin/auth/JellyfinLoginActivity.kt b/app/src/main/java/com/lostf1sh/pixelplayeross/presentation/jellyfin/auth/JellyfinLoginActivity.kt index 84cdcdc..51470ca 100644 --- a/app/src/main/java/com/lostf1sh/pixelplayeross/presentation/jellyfin/auth/JellyfinLoginActivity.kt +++ b/app/src/main/java/com/lostf1sh/pixelplayeross/presentation/jellyfin/auth/JellyfinLoginActivity.kt @@ -347,16 +347,20 @@ fun JellyfinLoginScreen( FilledTonalButton( onClick = { - if (serverUrl.isBlank()) { - serverUrl = "http://" + serverUrl = when { + serverUrl.isBlank() -> "http://" + serverUrl.startsWith("https://", ignoreCase = true) -> + "http://" + serverUrl.drop("https://".length) + serverUrl.startsWith("http://", ignoreCase = true) -> serverUrl + else -> "http://$serverUrl" } }, - enabled = !isLoading && serverUrl.isBlank(), + enabled = !isLoading && !serverUrl.startsWith("http://", ignoreCase = true), shape = inputShape, contentPadding = PaddingValues(horizontal = 14.dp, vertical = 10.dp) ) { Text( - text = stringResource(R.string.auth_prefill_http), + text = stringResource(R.string.auth_use_http), fontFamily = RoundedSans, fontWeight = FontWeight.Medium ) diff --git a/app/src/main/res/values/strings_auth.xml b/app/src/main/res/values/strings_auth.xml index 513a34f..acb301e 100644 --- a/app/src/main/res/values/strings_auth.xml +++ b/app/src/main/res/values/strings_auth.xml @@ -25,6 +25,7 @@ App password also works if your server supports it. App password also works if your server supports it. Prefill http:// + Use HTTP / VPN Compatible with Navidrome, Gonic, Airsonic, and other Subsonic-compatible servers Navidrome Subsonic @@ -35,7 +36,7 @@ Connect to your Jellyfin media server Enter your Jellyfin server URL and account credentials. http://192.168.1.100:8096 - Full URL of your Jellyfin server, including port. + Full URL including port. Local, Tailscale, and .local addresses can use HTTP. Your Jellyfin account username. Your Jellyfin account password. Connects to Jellyfin servers for streaming your music library diff --git a/app/src/test/java/com/lostf1sh/pixelplayeross/data/jellyfin/model/JellyfinCredentialsTest.kt b/app/src/test/java/com/lostf1sh/pixelplayeross/data/jellyfin/model/JellyfinCredentialsTest.kt index 6ca00ba..9de94e7 100644 --- a/app/src/test/java/com/lostf1sh/pixelplayeross/data/jellyfin/model/JellyfinCredentialsTest.kt +++ b/app/src/test/java/com/lostf1sh/pixelplayeross/data/jellyfin/model/JellyfinCredentialsTest.kt @@ -66,10 +66,23 @@ class JellyfinCredentialsTest { } @Test - fun `normalization prepends https and trims trailing slash`() { + fun `normalization prepends https for public hosts and trims trailing slash`() { assertEquals( "https://jellyfin.example.com", JellyfinCredentials(serverUrl = "jellyfin.example.com/", username = "u", password = "p").normalizedServerUrl ) } + + @Test + fun `normalization prepends http for local and vpn hosts`() { + mapOf( + "192.168.1.50:8096/" to "http://192.168.1.50:8096", + "100.64.12.34:8096/" to "http://100.64.12.34:8096", + "jellyfin.tailnet.ts.net:8096/" to "http://jellyfin.tailnet.ts.net:8096", + "musicbox:8096/" to "http://musicbox:8096" + ).forEach { (input, expected) -> + assertEquals(expected, creds(input).normalizedServerUrl) + assertNull(creds(input).connectionValidationError()) + } + } }