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())
+ }
+ }
}