Update dependencies and improve server discovery

This commit is contained in:
Jarne Demeulemeester 2021-10-23 17:39:46 +02:00
parent 69503f504d
commit e9e849d9e4
No known key found for this signature in database
GPG key ID: B61B7B150DB6A6D2
4 changed files with 85 additions and 31 deletions

View file

@ -84,8 +84,8 @@ dependencies {
implementation("androidx.preference:preference-ktx:$preferenceVersion") implementation("androidx.preference:preference-ktx:$preferenceVersion")
// Jellyfin // Jellyfin
val jellyfinVersion = "1.0.3" val jellyfinVersion = "1.1.0"
implementation("org.jellyfin.sdk:jellyfin-platform-android:$jellyfinVersion") implementation("org.jellyfin.sdk:jellyfin-core:$jellyfinVersion")
// Glide // Glide
val glideVersion = "4.12.0" val glideVersion = "4.12.0"
@ -93,12 +93,12 @@ dependencies {
kapt("com.github.bumptech.glide:compiler:$glideVersion") kapt("com.github.bumptech.glide:compiler:$glideVersion")
// Hilt // Hilt
val hiltVersion = "2.38.1" val hiltVersion = "2.39.1"
implementation("com.google.dagger:hilt-android:$hiltVersion") implementation("com.google.dagger:hilt-android:$hiltVersion")
kapt("com.google.dagger:hilt-compiler:$hiltVersion") kapt("com.google.dagger:hilt-compiler:$hiltVersion")
// ExoPlayer // 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-core:$exoplayerVersion")
implementation("com.google.android.exoplayer:exoplayer-ui:$exoplayerVersion") implementation("com.google.android.exoplayer:exoplayer-ui:$exoplayerVersion")
implementation(files("libs/extension-ffmpeg-release.aar")) implementation(files("libs/extension-ffmpeg-release.aar"))

View file

@ -2,9 +2,8 @@ package dev.jdtech.jellyfin.api
import android.content.Context import android.content.Context
import dev.jdtech.jellyfin.BuildConfig import dev.jdtech.jellyfin.BuildConfig
import org.jellyfin.sdk.Jellyfin import org.jellyfin.sdk.api.client.extensions.*
import org.jellyfin.sdk.android import org.jellyfin.sdk.createJellyfin
import org.jellyfin.sdk.api.operations.*
import org.jellyfin.sdk.model.ClientInfo import org.jellyfin.sdk.model.ClientInfo
import java.util.* import java.util.*
@ -12,29 +11,29 @@ import java.util.*
/** /**
* Jellyfin API class using org.jellyfin.sdk:jellyfin-platform-android * 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 * @param baseUrl The url of the server
* @constructor Creates a new [JellyfinApi] instance * @constructor Creates a new [JellyfinApi] instance
*/ */
class JellyfinApi(context: Context, baseUrl: String) { class JellyfinApi(androidContext: Context, baseUrl: String) {
val jellyfin = Jellyfin { val jellyfin = createJellyfin {
clientInfo = clientInfo =
ClientInfo(name = context.applicationInfo.loadLabel(context.packageManager).toString(), version = BuildConfig.VERSION_NAME) ClientInfo(name = androidContext.applicationInfo.loadLabel(androidContext.packageManager).toString(), version = BuildConfig.VERSION_NAME)
android(context) context = androidContext
} }
val api = jellyfin.createApi(baseUrl = baseUrl) val api = jellyfin.createApi(baseUrl = baseUrl)
var userId: UUID? = null var userId: UUID? = null
val systemApi = SystemApi(api) val systemApi = api.systemApi
val userApi = UserApi(api) val userApi = api.userApi
val viewsApi = UserViewsApi(api) val viewsApi = api.userViewsApi
val itemsApi = ItemsApi(api) val itemsApi = api.itemsApi
val userLibraryApi = UserLibraryApi(api) val userLibraryApi = api.userLibraryApi
val showsApi = TvShowsApi(api) val showsApi = api.tvShowsApi
val sessionApi = SessionApi(api) val sessionApi = api.sessionApi
val videosApi = VideosApi(api) val videosApi = api.videosApi
val mediaInfoApi = MediaInfoApi(api) val mediaInfoApi = api.mediaInfoApi
val playStateApi = PlayStateApi(api) val playStateApi = api.playStateApi
companion object { companion object {
@Volatile @Volatile

View file

@ -1,19 +1,22 @@
package dev.jdtech.jellyfin.viewmodels package dev.jdtech.jellyfin.viewmodels
import android.widget.Toast
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import dev.jdtech.jellyfin.BaseApplication
import dev.jdtech.jellyfin.api.JellyfinApi import dev.jdtech.jellyfin.api.JellyfinApi
import dev.jdtech.jellyfin.database.Server import dev.jdtech.jellyfin.database.Server
import dev.jdtech.jellyfin.database.ServerDatabaseDao import dev.jdtech.jellyfin.database.ServerDatabaseDao
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.jellyfin.sdk.discovery.RecommendedServerInfo import org.jellyfin.sdk.discovery.RecommendedServerInfo
import org.jellyfin.sdk.discovery.RecommendedServerInfoScore import org.jellyfin.sdk.discovery.RecommendedServerInfoScore
import org.jellyfin.sdk.discovery.RecommendedServerIssue
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -21,6 +24,7 @@ import javax.inject.Inject
class AddServerViewModel class AddServerViewModel
@Inject @Inject
constructor( constructor(
private val application: BaseApplication,
private val jellyfinApi: JellyfinApi, private val jellyfinApi: JellyfinApi,
private val database: ServerDatabaseDao private val database: ServerDatabaseDao
) : ViewModel() { ) : ViewModel() {
@ -45,24 +49,45 @@ constructor(
val candidates = jellyfinApi.jellyfin.discovery.getAddressCandidates(inputValue) val candidates = jellyfinApi.jellyfin.discovery.getAddressCandidates(inputValue)
val recommended = jellyfinApi.jellyfin.discovery.getRecommendedServers( val recommended = jellyfinApi.jellyfin.discovery.getRecommendedServers(
candidates, candidates,
RecommendedServerInfoScore.GOOD RecommendedServerInfoScore.OK
) )
val recommendedServer: RecommendedServerInfo
try { // Check if any servers have been found
recommendedServer = recommended.first() if (recommended.toList().isNullOrEmpty()) {
} catch (e: NoSuchElementException) {
throw Exception("Server not found") 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 { jellyfinApi.apply {
api.baseUrl = recommendedServer.address api.baseUrl = recommendedServer.address
api.accessToken = null 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" _error.value = "Server already added"
_navigateToLogin.value = false _navigateToLogin.value = false
} else { } 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<String>()
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 * Check if server is already in database using server ID
* *

View file

@ -9,7 +9,7 @@ buildscript {
} }
} }
dependencies { 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") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong