Filter out future content for recently released rows (#1436)

## Description
Don't show future content (episodes, etc) on recently released rows in
recommended tabs or home page rows.

### Related issues
Closes #262
Replaces #1262

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
The original PR #1262 author used claude. Some of that code that was
retained in this PR was reviewed & tested.

---------

Co-authored-by: ADT95 <turner7@outlook.com>
This commit is contained in:
Damontecres 2026-05-22 15:48:11 -04:00 committed by GitHub
parent df2dd3e7ca
commit c68ab33f38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 70 additions and 21 deletions

View file

@ -66,6 +66,7 @@ import org.jellyfin.sdk.model.api.request.GetRecordingsRequest
import org.jellyfin.sdk.model.api.request.GetStudiosRequest import org.jellyfin.sdk.model.api.request.GetStudiosRequest
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
import java.time.LocalDateTime
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -800,10 +801,22 @@ class HomeSettingsService
GetItemsRequest( GetItemsRequest(
parentId = row.parentId, parentId = row.parentId,
limit = limit, limit = limit,
sortBy = listOf(ItemSortBy.PREMIERE_DATE), sortBy =
sortOrder = listOf(SortOrder.DESCENDING), listOf(
ItemSortBy.PREMIERE_DATE,
ItemSortBy.SERIES_SORT_NAME,
ItemSortBy.AIRED_EPISODE_ORDER,
),
sortOrder =
listOf(
SortOrder.DESCENDING,
SortOrder.ASCENDING,
SortOrder.DESCENDING,
),
fields = DefaultItemFields, fields = DefaultItemFields,
recursive = true, recursive = true,
maxPremiereDate = LocalDateTime.now(),
isUnaired = false,
) )
if (usePaging) { if (usePaging) {
ApiRequestPager( ApiRequestPager(

View file

@ -14,7 +14,6 @@ import com.github.damontecres.wholphin.ui.data.SortAndDirection
import com.github.damontecres.wholphin.ui.gt import com.github.damontecres.wholphin.ui.gt
import com.github.damontecres.wholphin.ui.indexOfFirstOrNull import com.github.damontecres.wholphin.ui.indexOfFirstOrNull
import com.github.damontecres.wholphin.ui.playback.playable import com.github.damontecres.wholphin.ui.playback.playable
import com.github.damontecres.wholphin.ui.toBaseItems
import com.github.damontecres.wholphin.ui.toServerString import com.github.damontecres.wholphin.ui.toServerString
import com.github.damontecres.wholphin.util.ApiRequestPager import com.github.damontecres.wholphin.util.ApiRequestPager
import com.github.damontecres.wholphin.util.GetEpisodesRequestHandler import com.github.damontecres.wholphin.util.GetEpisodesRequestHandler
@ -24,13 +23,13 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.playlistsApi import org.jellyfin.sdk.api.client.extensions.playlistsApi
import org.jellyfin.sdk.api.client.extensions.userLibraryApi
import org.jellyfin.sdk.api.client.extensions.videosApi import org.jellyfin.sdk.api.client.extensions.videosApi
import org.jellyfin.sdk.model.api.BaseItemDto import org.jellyfin.sdk.model.api.BaseItemDto
import org.jellyfin.sdk.model.api.BaseItemKind import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.CreatePlaylistDto import org.jellyfin.sdk.model.api.CreatePlaylistDto
import org.jellyfin.sdk.model.api.ImageType import org.jellyfin.sdk.model.api.ImageType
import org.jellyfin.sdk.model.api.ItemSortBy import org.jellyfin.sdk.model.api.ItemSortBy
import org.jellyfin.sdk.model.api.LocationType
import org.jellyfin.sdk.model.api.MediaType import org.jellyfin.sdk.model.api.MediaType
import org.jellyfin.sdk.model.api.PlaylistUserPermissions import org.jellyfin.sdk.model.api.PlaylistUserPermissions
import org.jellyfin.sdk.model.api.SortOrder import org.jellyfin.sdk.model.api.SortOrder
@ -57,7 +56,7 @@ class PlaylistCreator
/** /**
* Creates a playlist of next up episodes for the given series starting with the given episode * Creates a playlist of next up episodes for the given series starting with the given episode
*/ */
suspend fun createFromEpisode( private suspend fun createFromEpisode(
seriesId: UUID, seriesId: UUID,
episodeId: UUID?, episodeId: UUID?,
seasonId: UUID? = null, seasonId: UUID? = null,
@ -85,7 +84,7 @@ class PlaylistCreator
/** /**
* Create from a server playlist ID * Create from a server playlist ID
*/ */
suspend fun createFromPlaylistId( private suspend fun createFromPlaylistId(
playlistId: UUID, playlistId: UUID,
startIndex: Int?, startIndex: Int?,
sortAndDirection: SortAndDirection, sortAndDirection: SortAndDirection,
@ -101,6 +100,7 @@ class PlaylistCreator
limit = Playlist.MAX_SIZE, limit = Playlist.MAX_SIZE,
sortBy = listOf(sortAndDirection.sort), sortBy = listOf(sortAndDirection.sort),
sortOrder = listOf(sortAndDirection.direction), sortOrder = listOf(sortAndDirection.direction),
excludeLocationTypes = listOf(LocationType.VIRTUAL),
), ),
) )
val items = GetItemsRequestHandler.execute(api, request).content.items val items = GetItemsRequestHandler.execute(api, request).content.items
@ -139,6 +139,7 @@ class PlaylistCreator
fields = DefaultItemFields, fields = DefaultItemFields,
startIndex = startIndex, startIndex = startIndex,
limit = Playlist.MAX_SIZE, limit = Playlist.MAX_SIZE,
excludeLocationTypes = listOf(LocationType.VIRTUAL),
), ),
) )
val items = val items =
@ -279,16 +280,18 @@ class PlaylistCreator
private suspend fun List<BaseItemDto>.convertAndAddParts(useSeriesForPrimary: Boolean = false): List<PlaylistItem> = private suspend fun List<BaseItemDto>.convertAndAddParts(useSeriesForPrimary: Boolean = false): List<PlaylistItem> =
buildList { buildList {
this@convertAndAddParts.forEach { ep -> this@convertAndAddParts
add(PlaylistItem.Media(BaseItem(ep, useSeriesForPrimary))) .filter { it.locationType != LocationType.VIRTUAL }
if (ep.partCount.gt(1)) { .forEach { ep ->
val parts = add(PlaylistItem.Media(BaseItem(ep, useSeriesForPrimary)))
api.videosApi.getAdditionalPart(ep.id).content.items.map { part -> if (ep.partCount.gt(1)) {
PlaylistItem.Media(BaseItem(part, useSeriesForPrimary)) val parts =
} api.videosApi.getAdditionalPart(ep.id).content.items.map { part ->
addAll(parts) PlaylistItem.Media(BaseItem(part, useSeriesForPrimary))
}
addAll(parts)
}
} }
}
} }
/** /**

View file

@ -15,6 +15,7 @@ import org.jellyfin.sdk.model.api.ItemSortBy
import org.jellyfin.sdk.model.api.SortOrder import org.jellyfin.sdk.model.api.SortOrder
import org.jellyfin.sdk.model.api.request.GetItemsRequest import org.jellyfin.sdk.model.api.request.GetItemsRequest
import org.jellyfin.sdk.model.api.request.GetResumeItemsRequest import org.jellyfin.sdk.model.api.request.GetResumeItemsRequest
import java.time.LocalDateTime
import java.util.UUID import java.util.UUID
private fun getRecommendedRows(parentId: UUID) = private fun getRecommendedRows(parentId: UUID) =
@ -41,9 +42,18 @@ private fun getRecommendedRows(parentId: UUID) =
includeItemTypes = listOf(BaseItemKind.MOVIE), includeItemTypes = listOf(BaseItemKind.MOVIE),
recursive = true, recursive = true,
enableUserData = true, enableUserData = true,
sortBy = listOf(ItemSortBy.PREMIERE_DATE), sortBy =
sortOrder = listOf(SortOrder.DESCENDING), listOf(
ItemSortBy.PREMIERE_DATE,
ItemSortBy.SORT_NAME,
),
sortOrder =
listOf(
SortOrder.DESCENDING,
SortOrder.ASCENDING,
),
enableTotalRecordCount = false, enableTotalRecordCount = false,
maxPremiereDate = LocalDateTime.now(),
), ),
), ),
RecommendedRow( RecommendedRow(

View file

@ -15,6 +15,7 @@ import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.ItemSortBy import org.jellyfin.sdk.model.api.ItemSortBy
import org.jellyfin.sdk.model.api.SortOrder import org.jellyfin.sdk.model.api.SortOrder
import org.jellyfin.sdk.model.api.request.GetItemsRequest import org.jellyfin.sdk.model.api.request.GetItemsRequest
import java.time.LocalDateTime
import java.util.UUID import java.util.UUID
private fun getRecommendedRows(parentId: UUID) = private fun getRecommendedRows(parentId: UUID) =
@ -29,9 +30,18 @@ private fun getRecommendedRows(parentId: UUID) =
includeItemTypes = listOf(BaseItemKind.MUSIC_ALBUM), includeItemTypes = listOf(BaseItemKind.MUSIC_ALBUM),
recursive = true, recursive = true,
enableUserData = true, enableUserData = true,
sortBy = listOf(ItemSortBy.PREMIERE_DATE), sortBy =
sortOrder = listOf(SortOrder.DESCENDING), listOf(
ItemSortBy.PREMIERE_DATE,
ItemSortBy.SORT_NAME,
),
sortOrder =
listOf(
SortOrder.DESCENDING,
SortOrder.ASCENDING,
),
enableTotalRecordCount = false, enableTotalRecordCount = false,
maxPremiereDate = LocalDateTime.now(),
), ),
), ),
RecommendedRow( RecommendedRow(

View file

@ -17,6 +17,7 @@ import org.jellyfin.sdk.model.api.SortOrder
import org.jellyfin.sdk.model.api.request.GetItemsRequest import org.jellyfin.sdk.model.api.request.GetItemsRequest
import org.jellyfin.sdk.model.api.request.GetNextUpRequest import org.jellyfin.sdk.model.api.request.GetNextUpRequest
import org.jellyfin.sdk.model.api.request.GetResumeItemsRequest import org.jellyfin.sdk.model.api.request.GetResumeItemsRequest
import java.time.LocalDateTime
import java.util.UUID import java.util.UUID
private fun getRecommendedRows( private fun getRecommendedRows(
@ -58,9 +59,21 @@ private fun getRecommendedRows(
includeItemTypes = listOf(BaseItemKind.EPISODE), includeItemTypes = listOf(BaseItemKind.EPISODE),
recursive = true, recursive = true,
enableUserData = true, enableUserData = true,
sortBy = listOf(ItemSortBy.PREMIERE_DATE), sortBy =
sortOrder = listOf(SortOrder.DESCENDING), listOf(
ItemSortBy.PREMIERE_DATE,
ItemSortBy.SERIES_SORT_NAME,
ItemSortBy.AIRED_EPISODE_ORDER,
),
sortOrder =
listOf(
SortOrder.DESCENDING,
SortOrder.ASCENDING,
SortOrder.DESCENDING,
),
enableTotalRecordCount = false, enableTotalRecordCount = false,
maxPremiereDate = LocalDateTime.now(),
isUnaired = false,
), ),
), ),
RecommendedRow( RecommendedRow(