From e9e849d9e4d3ff138d58ec3118d53f7a9db899ec Mon Sep 17 00:00:00 2001 From: Jarne Demeulemeester Date: Sat, 23 Oct 2021 17:39:46 +0200 Subject: [PATCH] Update dependencies and improve server discovery --- app/build.gradle.kts | 8 +-- .../dev/jdtech/jellyfin/api/JellyfinApi.kt | 35 +++++---- .../jellyfin/viewmodels/AddServerViewModel.kt | 71 ++++++++++++++++--- build.gradle.kts | 2 +- 4 files changed, 85 insertions(+), 31 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 30a96e5a..40309f38 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -84,8 +84,8 @@ dependencies { implementation("androidx.preference:preference-ktx:$preferenceVersion") // Jellyfin - val jellyfinVersion = "1.0.3" - implementation("org.jellyfin.sdk:jellyfin-platform-android:$jellyfinVersion") + val jellyfinVersion = "1.1.0" + implementation("org.jellyfin.sdk:jellyfin-core:$jellyfinVersion") // Glide val glideVersion = "4.12.0" @@ -93,12 +93,12 @@ dependencies { kapt("com.github.bumptech.glide:compiler:$glideVersion") // Hilt - val hiltVersion = "2.38.1" + val hiltVersion = "2.39.1" implementation("com.google.dagger:hilt-android:$hiltVersion") kapt("com.google.dagger:hilt-compiler:$hiltVersion") // ExoPlayer - val exoplayerVersion = "2.15.0" + val exoplayerVersion = "2.15.1" implementation("com.google.android.exoplayer:exoplayer-core:$exoplayerVersion") implementation("com.google.android.exoplayer:exoplayer-ui:$exoplayerVersion") implementation(files("libs/extension-ffmpeg-release.aar")) diff --git a/app/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt b/app/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt index 31df12b2..272e780f 100644 --- a/app/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt +++ b/app/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt @@ -2,9 +2,8 @@ package dev.jdtech.jellyfin.api import android.content.Context import dev.jdtech.jellyfin.BuildConfig -import org.jellyfin.sdk.Jellyfin -import org.jellyfin.sdk.android -import org.jellyfin.sdk.api.operations.* +import org.jellyfin.sdk.api.client.extensions.* +import org.jellyfin.sdk.createJellyfin import org.jellyfin.sdk.model.ClientInfo import java.util.* @@ -12,29 +11,29 @@ import java.util.* /** * Jellyfin API class using org.jellyfin.sdk:jellyfin-platform-android * - * @param context The context + * @param androidContext The context * @param baseUrl The url of the server * @constructor Creates a new [JellyfinApi] instance */ -class JellyfinApi(context: Context, baseUrl: String) { - val jellyfin = Jellyfin { +class JellyfinApi(androidContext: Context, baseUrl: String) { + val jellyfin = createJellyfin { clientInfo = - ClientInfo(name = context.applicationInfo.loadLabel(context.packageManager).toString(), version = BuildConfig.VERSION_NAME) - android(context) + ClientInfo(name = androidContext.applicationInfo.loadLabel(androidContext.packageManager).toString(), version = BuildConfig.VERSION_NAME) + context = androidContext } val api = jellyfin.createApi(baseUrl = baseUrl) var userId: UUID? = null - val systemApi = SystemApi(api) - val userApi = UserApi(api) - val viewsApi = UserViewsApi(api) - val itemsApi = ItemsApi(api) - val userLibraryApi = UserLibraryApi(api) - val showsApi = TvShowsApi(api) - val sessionApi = SessionApi(api) - val videosApi = VideosApi(api) - val mediaInfoApi = MediaInfoApi(api) - val playStateApi = PlayStateApi(api) + val systemApi = api.systemApi + val userApi = api.userApi + val viewsApi = api.userViewsApi + val itemsApi = api.itemsApi + val userLibraryApi = api.userLibraryApi + val showsApi = api.tvShowsApi + val sessionApi = api.sessionApi + val videosApi = api.videosApi + val mediaInfoApi = api.mediaInfoApi + val playStateApi = api.playStateApi companion object { @Volatile diff --git a/app/src/main/java/dev/jdtech/jellyfin/viewmodels/AddServerViewModel.kt b/app/src/main/java/dev/jdtech/jellyfin/viewmodels/AddServerViewModel.kt index 3f86da36..5a4662f8 100644 --- a/app/src/main/java/dev/jdtech/jellyfin/viewmodels/AddServerViewModel.kt +++ b/app/src/main/java/dev/jdtech/jellyfin/viewmodels/AddServerViewModel.kt @@ -1,19 +1,22 @@ package dev.jdtech.jellyfin.viewmodels +import android.widget.Toast import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import dev.jdtech.jellyfin.BaseApplication import dev.jdtech.jellyfin.api.JellyfinApi import dev.jdtech.jellyfin.database.Server import dev.jdtech.jellyfin.database.ServerDatabaseDao import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.jellyfin.sdk.discovery.RecommendedServerInfo import org.jellyfin.sdk.discovery.RecommendedServerInfoScore +import org.jellyfin.sdk.discovery.RecommendedServerIssue import timber.log.Timber import javax.inject.Inject @@ -21,6 +24,7 @@ import javax.inject.Inject class AddServerViewModel @Inject constructor( + private val application: BaseApplication, private val jellyfinApi: JellyfinApi, private val database: ServerDatabaseDao ) : ViewModel() { @@ -45,24 +49,45 @@ constructor( val candidates = jellyfinApi.jellyfin.discovery.getAddressCandidates(inputValue) val recommended = jellyfinApi.jellyfin.discovery.getRecommendedServers( candidates, - RecommendedServerInfoScore.GOOD + RecommendedServerInfoScore.OK ) - val recommendedServer: RecommendedServerInfo - try { - recommendedServer = recommended.first() - } catch (e: NoSuchElementException) { + // Check if any servers have been found + if (recommended.toList().isNullOrEmpty()) { throw Exception("Server not found") } + // Create separate flow of great, good and ok servers. + val greatServers = + recommended.filter { it.score == RecommendedServerInfoScore.GREAT } + val goodServers = recommended.filter { it.score == RecommendedServerInfoScore.GOOD } + val okServers = recommended.filter { it.score == RecommendedServerInfoScore.OK } + + // Only allow connecting to great and good servers. Show toast of issues if good server + val recommendedServer = if (greatServers.toList().isNotEmpty()) { + greatServers.first() + } else if (goodServers.toList().isNotEmpty()) { + val issuesString = createIssuesString(goodServers.first()) + Toast.makeText( + application, + issuesString, + Toast.LENGTH_LONG + ).show() + goodServers.first() + } else { + val okServer = okServers.first() + val issuesString = createIssuesString(okServer) + throw Exception(issuesString) + } + jellyfinApi.apply { api.baseUrl = recommendedServer.address api.accessToken = null } - Timber.d("Remote server: ${recommendedServer.systemInfo?.id}") + Timber.d("Remote server: ${recommendedServer.systemInfo.getOrNull()?.id}") - if (serverAlreadyInDatabase(recommendedServer.systemInfo?.id)) { + if (serverAlreadyInDatabase(recommendedServer.systemInfo.getOrNull()?.id)) { _error.value = "Server already added" _navigateToLogin.value = false } else { @@ -77,6 +102,36 @@ constructor( } } + /** + * Create a presentable string of issues with a server + * + * @param server The server with issues + * @return A presentable string of issues separated with \n + */ + private fun createIssuesString(server: RecommendedServerInfo): String { + val issues = mutableListOf() + server.issues.forEach { + when (it) { + is RecommendedServerIssue.OutdatedServerVersion -> { + issues.add("Server version outdated: ${it.version} \nPlease update your server") + } + is RecommendedServerIssue.InvalidProductName -> { + issues.add("Not a Jellyfin server: ${it.productName}") + } + is RecommendedServerIssue.UnsupportedServerVersion -> { + issues.add("Unsupported server version: ${it.version} \nPlease update your server") + } + is RecommendedServerIssue.SlowResponse -> { + issues.add("Server is too slow to respond: ${it.responseTime}") + } + else -> { + issues.add("Unknown error") + } + } + } + return issues.joinToString("\n") + } + /** * Check if server is already in database using server ID * diff --git a/build.gradle.kts b/build.gradle.kts index 08ebb2fe..2288d07a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ buildscript { } } dependencies { - classpath("com.android.tools.build:gradle:7.0.2") + classpath("com.android.tools.build:gradle:7.0.3") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") // NOTE: Do not place your application dependencies here; they belong