Clean up & documentation

This commit is contained in:
Damontecres 2026-01-06 20:06:31 -05:00
parent 8612598d94
commit f43ee6b36c
No known key found for this signature in database
11 changed files with 44 additions and 30 deletions

View file

@ -15,7 +15,7 @@ plugins {
alias(libs.plugins.protobuf)
alias(libs.plugins.kotlin.plugin.serialization)
alias(libs.plugins.aboutLibraries)
id("org.openapi.generator") version "7.17.0"
alias(libs.plugins.openapi.generator)
}
val isCI = if (System.getenv("CI") != null) System.getenv("CI").toBoolean() else false
@ -72,14 +72,6 @@ android {
jvmTarget = JvmTarget.JVM_11
javaParameters = true
}
// sourceSets {
// main {
// java.srcDirs +=
// kotlin {
// srcDirs += files("$buildDir/generated/seerr_api/src/main/kotlin")
// }
// }
// }
}
buildFeatures {
buildConfig = true

View file

@ -71,6 +71,9 @@ enum class SeerrAvailability(
}
}
/**
* An item provided by a discovery service (ie Seerr). It may exist on the JF server as well.
*/
@Serializable
data class DiscoverItem(
val id: Int,

View file

@ -1,22 +1,17 @@
package com.github.damontecres.wholphin.services
import android.content.Context
import com.github.damontecres.wholphin.api.seerr.SeerrApiClient
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
import dagger.hilt.android.qualifiers.ApplicationContext
import okhttp3.OkHttpClient
/**
* Wrapper for [SeerrApiClient]. In most cases, you should use [SeerrService] instead.
*/
class SeerrApi(
@param:ApplicationContext private val context: Context,
private val okHttpClient: OkHttpClient,
) {
// private val prefs: SharedPreferences =
// context.getSharedPreferences("seerr", Context.MODE_PRIVATE)
var api: SeerrApiClient =
SeerrApiClient(
// prefs.getString("baseUrl", null)!! + "/api/v1",
// prefs.getString("apiKey", null)!!,
baseUrl = "",
apiKey = null,
okHttpClient = okHttpClient,

View file

@ -28,6 +28,9 @@ import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
/**
* Manages saves/loading Seerr servers from the local DB. Also will update the current [SeerrApi] as needed.
*/
@Singleton
class SeerrServerRepository
@Inject
@ -147,6 +150,9 @@ class SeerrServerRepository
}
}
/**
* A [SeerrUser] config
*/
typealias SeerrUserConfig = User
data class CurrentSeerr(
@ -185,6 +191,9 @@ private suspend fun login(
}
}
/**
* Listens for JF user switching in the app to also switch the Seerr user/server
*/
@ActivityScoped
class UserSwitchListener
@Inject
@ -196,11 +205,10 @@ class UserSwitchListener
private val seerrApi: SeerrApi,
) {
init {
Timber.v("Launching")
context as AppCompatActivity
context.lifecycleScope.launchIO {
serverRepository.currentUser.asFlow().collect { user ->
Timber.v("New user")
Timber.d("New user")
seerrServerRepository.clear()
if (user != null) {
seerrServerDao

View file

@ -4,21 +4,28 @@ import com.github.damontecres.wholphin.api.seerr.SeerrApiClient
import com.github.damontecres.wholphin.api.seerr.model.SearchGet200ResponseResultsInner
import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.DiscoverItem
import kotlinx.coroutines.flow.first
import org.jellyfin.sdk.model.api.BaseItemKind
import javax.inject.Inject
import javax.inject.Singleton
typealias SeerrSearchResult = SearchGet200ResponseResultsInner
/**
* Main access for the current Seerr server (if any)
*
* Exposes a [SeerrApiClient] for queries
*/
@Singleton
class SeerrService
@Inject
constructor(
private val seerApi: SeerrApi,
private val seerrServerRepository: SeerrServerRepository,
) {
val api: SeerrApiClient get() = seerApi.api
val active: Boolean get() = seerApi.active
val active get() = seerrServerRepository.active
suspend fun search(
query: String,
@ -43,8 +50,15 @@ class SeerrService
?.map(::DiscoverItem)
.orEmpty()
suspend fun similar(item: BaseItem): List<DiscoverItem> =
if (active) {
/**
* Get [DiscoverItem]s similar to the JF items such as movies, series, or people
*
* If Seerr integration is not active, this short circuits to return null
*
* @return the discovered items or null if no Seerr server configured
*/
suspend fun similar(item: BaseItem): List<DiscoverItem>? =
if (active.first()) {
item.data.providerIds
?.get("Tmdb")
?.toIntOrNull()
@ -88,6 +102,6 @@ class SeerrService
}
}.orEmpty()
} else {
emptyList()
null
}
}

View file

@ -179,7 +179,6 @@ object AppModule {
@Provides
@Singleton
fun seerrApi(
@ApplicationContext context: Context,
@StandardOkHttpClient okHttpClient: OkHttpClient,
) = SeerrApi(context, okHttpClient)
) = SeerrApi(okHttpClient)
}

View file

@ -130,7 +130,7 @@ class PersonViewModel
episodes.setValueOnMain(RowLoadingState.Success(listOf()))
}
viewModelScope.launchIO {
val results = seerrService.similar(person)
val results = seerrService.similar(person).orEmpty()
discovered.update { results }
}
}

View file

@ -147,7 +147,7 @@ class MovieViewModel
this@MovieViewModel.extras.setValueOnMain(extras)
}
viewModelScope.launchIO {
val results = seerrService.similar(item)
val results = seerrService.similar(item).orEmpty()
discovered.update { results }
}

View file

@ -215,7 +215,7 @@ class SeriesViewModel
}
}
viewModelScope.launchIO {
val results = seerrService.similar(item)
val results = seerrService.similar(item).orEmpty()
discovered.update { results }
}
}

View file

@ -65,6 +65,7 @@ import com.github.damontecres.wholphin.util.GetItemsRequestHandler
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.jellyfin.sdk.api.client.ApiClient
@ -144,8 +145,8 @@ class SearchViewModel
}
private fun searchSeerr(query: String) {
if (seerrService.active) {
viewModelScope.launchIO {
viewModelScope.launchIO {
if (seerrService.active.first()) {
seerrResults.setValueOnMain(SearchResult.Searching)
val results =
seerrService