From f43ee6b36c14c4b1a6ef87d9a13b6e63b3de6efc Mon Sep 17 00:00:00 2001 From: Damontecres Date: Tue, 6 Jan 2026 20:06:31 -0500 Subject: [PATCH] Clean up & documentation --- app/build.gradle.kts | 10 +-------- .../wholphin/data/model/DiscoverItem.kt | 3 +++ .../damontecres/wholphin/services/SeerrApi.kt | 11 +++------- .../services/SeerrServerRepository.kt | 12 ++++++++-- .../wholphin/services/SeerrService.kt | 22 +++++++++++++++---- .../wholphin/services/hilt/AppModule.kt | 3 +-- .../wholphin/ui/detail/PersonPage.kt | 2 +- .../ui/detail/movie/MovieViewModel.kt | 2 +- .../ui/detail/series/SeriesViewModel.kt | 2 +- .../wholphin/ui/main/SearchPage.kt | 5 +++-- gradle/libs.versions.toml | 2 ++ 11 files changed, 44 insertions(+), 30 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e997870d..7be86078 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -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 diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/model/DiscoverItem.kt b/app/src/main/java/com/github/damontecres/wholphin/data/model/DiscoverItem.kt index 9c1960ec..fc307b34 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/data/model/DiscoverItem.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/data/model/DiscoverItem.kt @@ -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, diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/SeerrApi.kt b/app/src/main/java/com/github/damontecres/wholphin/services/SeerrApi.kt index 07415454..c68cd3d2 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/SeerrApi.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/SeerrApi.kt @@ -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, diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/SeerrServerRepository.kt b/app/src/main/java/com/github/damontecres/wholphin/services/SeerrServerRepository.kt index 5318aba8..d846b6ee 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/SeerrServerRepository.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/SeerrServerRepository.kt @@ -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 diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/SeerrService.kt b/app/src/main/java/com/github/damontecres/wholphin/services/SeerrService.kt index 3107408f..18511a58 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/SeerrService.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/SeerrService.kt @@ -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 = - 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? = + if (active.first()) { item.data.providerIds ?.get("Tmdb") ?.toIntOrNull() @@ -88,6 +102,6 @@ class SeerrService } }.orEmpty() } else { - emptyList() + null } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/hilt/AppModule.kt b/app/src/main/java/com/github/damontecres/wholphin/services/hilt/AppModule.kt index 66d8ca2f..e6ae832a 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/hilt/AppModule.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/hilt/AppModule.kt @@ -179,7 +179,6 @@ object AppModule { @Provides @Singleton fun seerrApi( - @ApplicationContext context: Context, @StandardOkHttpClient okHttpClient: OkHttpClient, - ) = SeerrApi(context, okHttpClient) + ) = SeerrApi(okHttpClient) } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PersonPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PersonPage.kt index 261a5a5d..01adf23e 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PersonPage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PersonPage.kt @@ -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 } } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/movie/MovieViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/movie/MovieViewModel.kt index ca571934..8454f0a1 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/movie/MovieViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/movie/MovieViewModel.kt @@ -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 } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt index aef74de1..9d6f1e94 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt @@ -215,7 +215,7 @@ class SeriesViewModel } } viewModelScope.launchIO { - val results = seerrService.similar(item) + val results = seerrService.similar(item).orEmpty() discovered.update { results } } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/SearchPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/SearchPage.kt index a8b9790b..4ca9f2c3 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/SearchPage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/SearchPage.kt @@ -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 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 61c5e8cf..61a3b478 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -40,6 +40,7 @@ preferenceKtx = "1.2.1" tvprovider = "1.1.0" workRuntimeKtx = "2.11.0" paletteKtx = "1.0.0" +openapi-generator = "7.17.0" [libraries] aboutlibraries-core = { module = "com.mikepenz:aboutlibraries-core", version.ref = "aboutLibraries" } @@ -130,3 +131,4 @@ protobuf = { id = "com.google.protobuf", version.ref = "protobuf" } hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } room = { id = "androidx.room", version.ref = "room" } aboutLibraries = { id = "com.mikepenz.aboutlibraries.plugin.android", version.ref = "aboutLibraries" } +openapi-generator = { id = "org.openapi.generator", version.ref = "openapi-generator" }