mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Support playing local movie trailers (#36)
Adds support for playing local movie trailers. External trailers, such as ones on YouTube, are not yet supported. Also fixes a couple issues with request handlers
This commit is contained in:
parent
bb19ba316b
commit
63baf7f904
6 changed files with 61 additions and 2 deletions
|
|
@ -35,7 +35,7 @@ fun ChapterRow(
|
|||
LazyRow(
|
||||
state = rememberLazyListState(),
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
contentPadding = PaddingValues(16.dp),
|
||||
contentPadding = PaddingValues(vertical = 8.dp, horizontal = 16.dp),
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(start = 16.dp)
|
||||
|
|
|
|||
|
|
@ -28,12 +28,15 @@ import androidx.compose.ui.focus.focusRequester
|
|||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.tv.material3.MaterialTheme
|
||||
import coil3.compose.AsyncImage
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.ChosenStreams
|
||||
import com.github.damontecres.wholphin.data.ItemPlaybackRepository
|
||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||
|
|
@ -42,8 +45,11 @@ import com.github.damontecres.wholphin.data.model.ItemPlayback
|
|||
import com.github.damontecres.wholphin.data.model.Person
|
||||
import com.github.damontecres.wholphin.data.model.chooseSource
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.ui.Cards
|
||||
import com.github.damontecres.wholphin.ui.cards.ChapterRow
|
||||
import com.github.damontecres.wholphin.ui.cards.ItemRow
|
||||
import com.github.damontecres.wholphin.ui.cards.PersonRow
|
||||
import com.github.damontecres.wholphin.ui.cards.SeasonCard
|
||||
import com.github.damontecres.wholphin.ui.components.DialogParams
|
||||
import com.github.damontecres.wholphin.ui.components.DialogPopup
|
||||
import com.github.damontecres.wholphin.ui.components.ErrorMessage
|
||||
|
|
@ -70,6 +76,7 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.withContext
|
||||
import org.jellyfin.sdk.api.client.ApiClient
|
||||
import org.jellyfin.sdk.api.client.extensions.playStateApi
|
||||
import org.jellyfin.sdk.api.client.extensions.userLibraryApi
|
||||
import org.jellyfin.sdk.model.api.MediaStreamType
|
||||
import org.jellyfin.sdk.model.extensions.ticks
|
||||
import org.jellyfin.sdk.model.serializer.toUUID
|
||||
|
|
@ -89,6 +96,7 @@ class MovieViewModel
|
|||
val people = MutableLiveData<List<Person>>(listOf())
|
||||
val chapters = MutableLiveData<List<Chapter>>(listOf())
|
||||
val chosenStreams = MutableLiveData<ChosenStreams?>(null)
|
||||
val trailers = MutableLiveData<List<BaseItem>>(listOf())
|
||||
|
||||
override fun init(
|
||||
itemId: UUID,
|
||||
|
|
@ -103,6 +111,16 @@ class MovieViewModel
|
|||
withContext(Dispatchers.Main) {
|
||||
chosenStreams.value = result
|
||||
}
|
||||
val localTrailerCount = item.data.localTrailerCount ?: 0
|
||||
if (localTrailerCount > 0) {
|
||||
val trailers =
|
||||
api.userLibraryApi.getLocalTrailers(itemId).content.map {
|
||||
BaseItem.from(it, api)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
this@MovieViewModel.trailers.value = trailers
|
||||
}
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
people.value =
|
||||
|
|
@ -180,6 +198,7 @@ fun MovieDetails(
|
|||
val item by viewModel.item.observeAsState()
|
||||
val people by viewModel.people.observeAsState(listOf())
|
||||
val chapters by viewModel.chapters.observeAsState(listOf())
|
||||
val trailers by viewModel.trailers.observeAsState(listOf())
|
||||
val loading by viewModel.loading.observeAsState(LoadingState.Loading)
|
||||
val chosenStreams by viewModel.chosenStreams.observeAsState(null)
|
||||
|
||||
|
|
@ -200,6 +219,7 @@ fun MovieDetails(
|
|||
chosenStreams = chosenStreams,
|
||||
people = people,
|
||||
chapters = chapters,
|
||||
trailers = trailers,
|
||||
playOnClick = {
|
||||
viewModel.navigationManager.navigateTo(
|
||||
Destination.Playback(
|
||||
|
|
@ -270,6 +290,15 @@ fun MovieDetails(
|
|||
watchOnClick = {
|
||||
viewModel.setWatched((movie.data.userData?.played ?: false).not())
|
||||
},
|
||||
trailerOnClick = { trailer ->
|
||||
viewModel.navigationManager.navigateTo(
|
||||
Destination.Playback(
|
||||
itemId = trailer.id,
|
||||
item = trailer,
|
||||
positionMs = 0L,
|
||||
),
|
||||
)
|
||||
},
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
|
@ -310,7 +339,9 @@ fun MovieDetailsContent(
|
|||
chosenStreams: ChosenStreams?,
|
||||
people: List<Person>,
|
||||
chapters: List<Chapter>,
|
||||
trailers: List<BaseItem>,
|
||||
playOnClick: (Duration) -> Unit,
|
||||
trailerOnClick: (BaseItem) -> Unit,
|
||||
overviewOnClick: () -> Unit,
|
||||
watchOnClick: () -> Unit,
|
||||
moreOnClick: () -> Unit,
|
||||
|
|
@ -359,7 +390,7 @@ fun MovieDetailsContent(
|
|||
}
|
||||
LazyColumn(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
contentPadding = PaddingValues(32.dp),
|
||||
contentPadding = PaddingValues(horizontal = 32.dp, vertical = 8.dp),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
item {
|
||||
|
|
@ -407,6 +438,27 @@ fun MovieDetailsContent(
|
|||
)
|
||||
}
|
||||
}
|
||||
if (trailers.isNotEmpty()) {
|
||||
item {
|
||||
ItemRow(
|
||||
title = stringResource(R.string.trailers),
|
||||
items = trailers,
|
||||
onClickItem = trailerOnClick,
|
||||
onLongClickItem = {},
|
||||
cardContent = @Composable { index, item, mod, onClick, onLongClick ->
|
||||
SeasonCard(
|
||||
item = item,
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
imageHeight = Cards.height2x3,
|
||||
imageWidth = Dp.Unspecified,
|
||||
showImageOverlay = false,
|
||||
modifier = mod,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
if (chapters.isNotEmpty()) {
|
||||
item {
|
||||
ChapterRow(
|
||||
|
|
|
|||
|
|
@ -476,6 +476,7 @@ class PlaybackViewModel
|
|||
it.release()
|
||||
player.removeListener(it)
|
||||
}
|
||||
|
||||
val activityListener =
|
||||
TrackActivityPlaybackListener(
|
||||
api = api,
|
||||
|
|
|
|||
|
|
@ -230,6 +230,7 @@ val GetResumeItemsRequestHandler =
|
|||
request.copy(
|
||||
startIndex = startIndex,
|
||||
limit = limit,
|
||||
enableTotalRecordCount = enableTotalRecordCount,
|
||||
)
|
||||
|
||||
override suspend fun execute(
|
||||
|
|
@ -249,6 +250,7 @@ val GetNextUpRequestHandler =
|
|||
request.copy(
|
||||
startIndex = startIndex,
|
||||
limit = limit,
|
||||
enableTotalRecordCount = enableTotalRecordCount,
|
||||
)
|
||||
|
||||
override suspend fun execute(
|
||||
|
|
@ -268,6 +270,7 @@ val GetSuggestionsRequestHandler =
|
|||
request.copy(
|
||||
startIndex = startIndex,
|
||||
limit = limit,
|
||||
enableTotalRecordCount = enableTotalRecordCount,
|
||||
)
|
||||
|
||||
override suspend fun execute(
|
||||
|
|
@ -306,6 +309,7 @@ val GetGenresRequestHandler =
|
|||
request.copy(
|
||||
startIndex = startIndex,
|
||||
limit = limit,
|
||||
enableTotalRecordCount = enableTotalRecordCount,
|
||||
)
|
||||
|
||||
override suspend fun execute(
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ val supportItemKinds =
|
|||
BaseItemKind.SEASON,
|
||||
BaseItemKind.COLLECTION_FOLDER,
|
||||
BaseItemKind.USER_VIEW,
|
||||
BaseItemKind.TRAILER,
|
||||
)
|
||||
|
||||
val supportedCollectionTypes =
|
||||
|
|
|
|||
|
|
@ -82,5 +82,6 @@
|
|||
<string name="playback_overrides">Playback overrides</string>
|
||||
<string name="direct_play_ass">Direct play ASS subtitles</string>
|
||||
<string name="direct_play_pgs">Direct play PGS subtitles</string>
|
||||
<string name="trailers">Trailers</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue