From 1816317c68a4ca8b6055dd99758b7940d972bfb5 Mon Sep 17 00:00:00 2001 From: Damontecres Date: Fri, 3 Oct 2025 15:11:26 -0400 Subject: [PATCH] Play theme songs for series --- .../damontecres/dolphin/MainActivity.kt | 4 +- .../damontecres/dolphin/hilt/AppModule.kt | 37 +++++++++++- .../damontecres/dolphin/ui/CoilConfig.kt | 16 +---- .../dolphin/ui/detail/SeriesDetails.kt | 60 +++++++++++++++++++ .../ui/detail/series/SeriesOverview.kt | 2 + 5 files changed, 102 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/github/damontecres/dolphin/MainActivity.kt b/app/src/main/java/com/github/damontecres/dolphin/MainActivity.kt index d4036443..4c533c2b 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/MainActivity.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/MainActivity.kt @@ -25,6 +25,7 @@ import androidx.tv.material3.ExperimentalTvMaterial3Api import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Surface import com.github.damontecres.dolphin.data.ServerRepository +import com.github.damontecres.dolphin.hilt.AuthOkHttpClient import com.github.damontecres.dolphin.preferences.AppPreferences import com.github.damontecres.dolphin.preferences.DefaultUserConfiguration import com.github.damontecres.dolphin.preferences.UserPreferences @@ -48,6 +49,7 @@ class MainActivity : AppCompatActivity() { @Inject lateinit var userPreferencesDataStore: DataStore + @AuthOkHttpClient @Inject lateinit var okHttpClient: OkHttpClient @@ -64,7 +66,7 @@ class MainActivity : AppCompatActivity() { .background(MaterialTheme.colorScheme.background), shape = RectangleShape, ) { - CoilConfig(serverRepository, okHttpClient, false) + CoilConfig(okHttpClient, false) var isRestoringSession by remember { mutableStateOf(true) } val appPreferences by userPreferencesDataStore.data.collectAsState(null) diff --git a/app/src/main/java/com/github/damontecres/dolphin/hilt/AppModule.kt b/app/src/main/java/com/github/damontecres/dolphin/hilt/AppModule.kt index ef34b18f..1d4f4706 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/hilt/AppModule.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/hilt/AppModule.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.content.Context import android.provider.Settings import com.github.damontecres.dolphin.BuildConfig +import com.github.damontecres.dolphin.data.ServerRepository import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -15,11 +16,21 @@ import org.jellyfin.sdk.api.okhttp.OkHttpFactory import org.jellyfin.sdk.createJellyfin import org.jellyfin.sdk.model.ClientInfo import org.jellyfin.sdk.model.DeviceInfo +import javax.inject.Qualifier import javax.inject.Singleton +@Qualifier +@Retention(AnnotationRetention.BINARY) +annotation class AuthOkHttpClient + +@Qualifier +@Retention(AnnotationRetention.BINARY) +annotation class StandardOkHttpClient + @Module @InstallIn(SingletonComponent::class) object AppModule { + @StandardOkHttpClient @Provides @Singleton fun okHttpClient() = @@ -29,9 +40,33 @@ object AppModule { // TODO user agent, timeouts, logging, etc }.build() + @AuthOkHttpClient @Provides @Singleton - fun okHttpFactory(okHttpClient: OkHttpClient) = OkHttpFactory(okHttpClient) + fun authOkHttpClient( + serverRepository: ServerRepository, + @StandardOkHttpClient okHttpClient: OkHttpClient, + ) = okHttpClient + .newBuilder() + .addInterceptor { + val request = it.request() + val newRequest = + serverRepository.currentUser?.accessToken?.let { token -> + request + .newBuilder() + .addHeader( + "Authorization", + "MediaBrowser Token=\"$token\"", + ).build() + } + it.proceed(newRequest ?: request) + }.build() + + @Provides + @Singleton + fun okHttpFactory( + @StandardOkHttpClient okHttpClient: OkHttpClient, + ) = OkHttpFactory(okHttpClient) @Provides @Singleton diff --git a/app/src/main/java/com/github/damontecres/dolphin/ui/CoilConfig.kt b/app/src/main/java/com/github/damontecres/dolphin/ui/CoilConfig.kt index 9b595047..c379b682 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/ui/CoilConfig.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/ui/CoilConfig.kt @@ -10,15 +10,12 @@ import coil3.network.cachecontrol.CacheControlCacheStrategy import coil3.network.okhttp.OkHttpNetworkFetcherFactory import coil3.request.crossfade import coil3.util.DebugLogger -import com.github.damontecres.dolphin.data.ServerRepository -import okhttp3.Call import okhttp3.OkHttpClient import kotlin.time.ExperimentalTime @OptIn(ExperimentalTime::class, ExperimentalCoilApi::class) @Composable fun CoilConfig( - serverRepository: ServerRepository, okHttpClient: OkHttpClient, debugLogging: Boolean, ) { @@ -37,18 +34,7 @@ fun CoilConfig( add( OkHttpNetworkFetcherFactory( cacheStrategy = { CacheControlCacheStrategy() }, - callFactory = { - Call.Factory { request -> - // Ref: https://gist.github.com/nielsvanvelzen/ea047d9028f676185832e51ffaf12a6f - val token = serverRepository.currentUser?.accessToken - okHttpClient.newCall( - request - .newBuilder() - .addHeader("Authorization", "MediaBrowser Token=\"$token\"") - .build(), - ) - } - }, + callFactory = { okHttpClient }, ), ) }.build() diff --git a/app/src/main/java/com/github/damontecres/dolphin/ui/detail/SeriesDetails.kt b/app/src/main/java/com/github/damontecres/dolphin/ui/detail/SeriesDetails.kt index a3631fdc..30bbfd7a 100644 --- a/app/src/main/java/com/github/damontecres/dolphin/ui/detail/SeriesDetails.kt +++ b/app/src/main/java/com/github/damontecres/dolphin/ui/detail/SeriesDetails.kt @@ -1,5 +1,7 @@ package com.github.damontecres.dolphin.ui.detail +import android.content.Context +import androidx.annotation.OptIn import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.runtime.Composable @@ -10,9 +12,16 @@ import androidx.compose.ui.Modifier import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope +import androidx.media3.common.MediaItem +import androidx.media3.common.Player +import androidx.media3.common.util.UnstableApi +import androidx.media3.datasource.okhttp.OkHttpDataSource +import androidx.media3.exoplayer.ExoPlayer +import androidx.media3.exoplayer.source.DefaultMediaSourceFactory import androidx.tv.material3.Text import com.github.damontecres.dolphin.data.model.BaseItem import com.github.damontecres.dolphin.data.model.Video +import com.github.damontecres.dolphin.hilt.AuthOkHttpClient import com.github.damontecres.dolphin.preferences.UserPreferences import com.github.damontecres.dolphin.ui.cards.ItemRow import com.github.damontecres.dolphin.ui.components.ErrorMessage @@ -26,12 +35,16 @@ import com.github.damontecres.dolphin.util.GetItemsRequestHandler import com.github.damontecres.dolphin.util.LoadingExceptionHandler import com.github.damontecres.dolphin.util.LoadingState import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import okhttp3.OkHttpClient import org.jellyfin.sdk.api.client.ApiClient +import org.jellyfin.sdk.api.client.extensions.libraryApi import org.jellyfin.sdk.api.client.extensions.playStateApi +import org.jellyfin.sdk.api.client.extensions.universalAudioApi import org.jellyfin.sdk.api.client.extensions.userLibraryApi import org.jellyfin.sdk.model.api.BaseItemKind import org.jellyfin.sdk.model.api.ItemFields @@ -48,7 +61,10 @@ class SeriesViewModel @Inject constructor( api: ApiClient, + @param:ApplicationContext val context: Context, + @param:AuthOkHttpClient private val okHttpClient: OkHttpClient, ) : ItemViewModel