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")
// 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"))

View file

@ -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

View file

@ -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<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
*

View file

@ -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