diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml
index e4f9ff23..4a014ff0 100644
--- a/composeApp/src/commonMain/composeResources/values/strings.xml
+++ b/composeApp/src/commonMain/composeResources/values/strings.xml
@@ -110,29 +110,38 @@
Production
Network
Collection
+ Person
+ Director
Custom
Pick a ready-made source. You can edit or remove it after adding.
Paste a public TMDB list URL or only the number from the URL.
Search by studio name, or paste a TMDB company ID/URL and add it directly.
Enter a network ID. Common networks are available in Presets and quick filters.
Search a movie collection name or paste the collection ID from TMDB.
+ Enter a TMDB person ID or URL to build a row from cast credits.
+ Enter a TMDB person ID or URL to build a row from director credits.
Build a live TMDB row using optional filters. Leave fields empty when you do not need that filter.
Public TMDB list
Network ID
Collection ID
+ Person ID
Production company name, ID, or URL
TMDB ID or URL
https://www.themoviedb.org/list/8504994 or 8504994
213 for Netflix, 49 for HBO, 2739 for Disney+
10 for Star Wars Collection
Marvel Studios, 420, or company URL
+ 31 for Tom Hanks, or person URL
Examples: Marvel Studios, 420, or https://www.themoviedb.org/company/420.
Example: Star Wars Collection, Harry Potter Collection, or a collection URL.
Example IDs: Netflix 213, HBO 49, Disney+ 2739.
Example: https://www.themoviedb.org/list/8504994 or 8504994.
+ Example: https://www.themoviedb.org/person/31-tom-hanks or 31.
Display title
Shown as the row/tab name. If blank, Nuvio creates one from the source.
Marvel Movies, Netflix Originals, Pixar
+ Tom Hanks Movies, Favorite Actors
+ Christopher Nolan Movies, Favorite Directors
Best Action Movies, Korean Dramas, 2024 Animation
Search Results
TMDB Collection
@@ -212,6 +221,7 @@
Disney+
Prime Video
Hulu
+ Original
Popular
Top Rated
Recent
@@ -219,6 +229,8 @@
TMDB Movie Collection
Production
Network
+ Person
+ Director
TMDB Discover
Create one to organize your catalogs.
No collections yet
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionEditorRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionEditorRepository.kt
index cbb476c8..f7597072 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionEditorRepository.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionEditorRepository.kt
@@ -46,6 +46,8 @@ enum class TmdbBuilderMode {
PRODUCTION,
NETWORK,
COLLECTION,
+ PERSON,
+ DIRECTOR,
DISCOVER,
}
@@ -340,9 +342,15 @@ object CollectionEditorRepository {
} else {
_uiState.value.tmdbMediaType
}
+ val sortBy = when (mode) {
+ TmdbBuilderMode.LIST,
+ TmdbBuilderMode.COLLECTION -> TmdbCollectionSort.ORIGINAL.value
+ else -> TmdbCollectionSort.POPULAR_DESC.value
+ }
_uiState.value = _uiState.value.copy(
tmdbBuilderMode = mode,
tmdbMediaType = mediaType,
+ tmdbSortBy = sortBy,
tmdbMediaBoth = if (
mode == TmdbBuilderMode.NETWORK ||
mode == TmdbBuilderMode.LIST ||
@@ -459,6 +467,8 @@ object CollectionEditorRepository {
TmdbBuilderMode.COLLECTION -> TmdbCollectionSourceType.COLLECTION
TmdbBuilderMode.PRODUCTION -> TmdbCollectionSourceType.COMPANY
TmdbBuilderMode.NETWORK -> TmdbCollectionSourceType.NETWORK
+ TmdbBuilderMode.PERSON -> TmdbCollectionSourceType.PERSON
+ TmdbBuilderMode.DIRECTOR -> TmdbCollectionSourceType.DIRECTOR
TmdbBuilderMode.DISCOVER -> TmdbCollectionSourceType.DISCOVER
}
val id = TmdbCollectionSourceResolver.parseTmdbId(state.tmdbInput)
@@ -473,6 +483,8 @@ object CollectionEditorRepository {
TmdbCollectionSourceType.COLLECTION -> "TMDB Collection ${id ?: ""}".trim()
TmdbCollectionSourceType.COMPANY -> "TMDB Production ${id ?: ""}".trim()
TmdbCollectionSourceType.NETWORK -> "TMDB Network ${id ?: ""}".trim()
+ TmdbCollectionSourceType.PERSON -> "TMDB Person ${id ?: ""}".trim()
+ TmdbCollectionSourceType.DIRECTOR -> "TMDB Director ${id ?: ""}".trim()
TmdbCollectionSourceType.DISCOVER -> "TMDB Discover"
}
}
@@ -561,6 +573,8 @@ private val coverMetadataSourceTypes = setOf(
TmdbCollectionSourceType.COLLECTION,
TmdbCollectionSourceType.COMPANY,
TmdbCollectionSourceType.NETWORK,
+ TmdbCollectionSourceType.PERSON,
+ TmdbCollectionSourceType.DIRECTOR,
)
private fun CollectionCatalogSource.toCollectionSource(): CollectionSource =
@@ -591,6 +605,8 @@ private fun selectedMediaTypes(
): List =
when (sourceType) {
TmdbCollectionSourceType.COMPANY,
+ TmdbCollectionSourceType.PERSON,
+ TmdbCollectionSourceType.DIRECTOR,
TmdbCollectionSourceType.DISCOVER -> if (state.tmdbMediaBoth) {
listOf(TmdbCollectionMediaType.MOVIE, TmdbCollectionMediaType.TV)
} else {
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionEditorScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionEditorScreen.kt
index 41ee6532..1a7bdf04 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionEditorScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionEditorScreen.kt
@@ -897,13 +897,19 @@ private fun TmdbSourcePickerScreen(
TmdbBuilderMode.COLLECTION -> TmdbCollectionSourceType.COLLECTION
TmdbBuilderMode.PRODUCTION -> TmdbCollectionSourceType.COMPANY
TmdbBuilderMode.NETWORK -> TmdbCollectionSourceType.NETWORK
+ TmdbBuilderMode.PERSON -> TmdbCollectionSourceType.PERSON
+ TmdbBuilderMode.DIRECTOR -> TmdbCollectionSourceType.DIRECTOR
TmdbBuilderMode.DISCOVER -> TmdbCollectionSourceType.DISCOVER
}
val requiresId = sourceType != TmdbCollectionSourceType.DISCOVER
val showMediaControls = state.tmdbBuilderMode == TmdbBuilderMode.PRODUCTION ||
+ state.tmdbBuilderMode == TmdbBuilderMode.PERSON ||
+ state.tmdbBuilderMode == TmdbBuilderMode.DIRECTOR ||
state.tmdbBuilderMode == TmdbBuilderMode.DISCOVER
val showSortControls = state.tmdbBuilderMode == TmdbBuilderMode.PRODUCTION ||
state.tmdbBuilderMode == TmdbBuilderMode.NETWORK ||
+ state.tmdbBuilderMode == TmdbBuilderMode.PERSON ||
+ state.tmdbBuilderMode == TmdbBuilderMode.DIRECTOR ||
state.tmdbBuilderMode == TmdbBuilderMode.DISCOVER
val showFilterControls = state.tmdbBuilderMode == TmdbBuilderMode.DISCOVER
@@ -1892,6 +1898,8 @@ private fun tmdbBuilderModeLabel(mode: TmdbBuilderMode): String =
TmdbBuilderMode.PRODUCTION -> stringResource(Res.string.collections_editor_tmdb_production_mode)
TmdbBuilderMode.NETWORK -> stringResource(Res.string.collections_editor_tmdb_network_mode)
TmdbBuilderMode.COLLECTION -> stringResource(Res.string.collections_editor_tmdb_collection_mode)
+ TmdbBuilderMode.PERSON -> stringResource(Res.string.collections_editor_tmdb_person_mode)
+ TmdbBuilderMode.DIRECTOR -> stringResource(Res.string.collections_editor_tmdb_director_mode)
TmdbBuilderMode.DISCOVER -> stringResource(Res.string.collections_editor_tmdb_custom_mode)
}
@@ -1903,6 +1911,8 @@ private fun tmdbModeHelpText(mode: TmdbBuilderMode): String =
TmdbBuilderMode.PRODUCTION -> stringResource(Res.string.collections_editor_tmdb_help_production)
TmdbBuilderMode.NETWORK -> stringResource(Res.string.collections_editor_tmdb_help_network)
TmdbBuilderMode.COLLECTION -> stringResource(Res.string.collections_editor_tmdb_help_collection)
+ TmdbBuilderMode.PERSON -> stringResource(Res.string.collections_editor_tmdb_help_person)
+ TmdbBuilderMode.DIRECTOR -> stringResource(Res.string.collections_editor_tmdb_help_director)
TmdbBuilderMode.DISCOVER -> stringResource(Res.string.collections_editor_tmdb_help_discover)
}
@@ -1913,6 +1923,8 @@ private fun tmdbInputLabel(mode: TmdbBuilderMode): String =
TmdbBuilderMode.NETWORK -> stringResource(Res.string.collections_editor_tmdb_network_id)
TmdbBuilderMode.COLLECTION -> stringResource(Res.string.collections_editor_tmdb_collection_id)
TmdbBuilderMode.PRODUCTION -> stringResource(Res.string.collections_editor_tmdb_company_search)
+ TmdbBuilderMode.PERSON,
+ TmdbBuilderMode.DIRECTOR -> stringResource(Res.string.collections_editor_tmdb_person_id)
else -> stringResource(Res.string.collections_editor_tmdb_id_or_url)
}
@@ -1923,6 +1935,8 @@ private fun tmdbInputPlaceholder(mode: TmdbBuilderMode): String =
TmdbBuilderMode.NETWORK -> stringResource(Res.string.collections_editor_tmdb_network_placeholder)
TmdbBuilderMode.COLLECTION -> stringResource(Res.string.collections_editor_tmdb_collection_placeholder)
TmdbBuilderMode.PRODUCTION -> stringResource(Res.string.collections_editor_tmdb_company_placeholder)
+ TmdbBuilderMode.PERSON,
+ TmdbBuilderMode.DIRECTOR -> stringResource(Res.string.collections_editor_tmdb_person_placeholder)
else -> stringResource(Res.string.collections_editor_tmdb_id_or_url)
}
@@ -1933,6 +1947,8 @@ private fun tmdbInputHelper(mode: TmdbBuilderMode): String =
TmdbBuilderMode.COLLECTION -> stringResource(Res.string.collections_editor_tmdb_collection_helper)
TmdbBuilderMode.NETWORK -> stringResource(Res.string.collections_editor_tmdb_network_helper)
TmdbBuilderMode.LIST -> stringResource(Res.string.collections_editor_tmdb_list_helper)
+ TmdbBuilderMode.PERSON,
+ TmdbBuilderMode.DIRECTOR -> stringResource(Res.string.collections_editor_tmdb_person_helper)
else -> ""
}
@@ -1940,12 +1956,15 @@ private fun tmdbInputHelper(mode: TmdbBuilderMode): String =
private fun tmdbTitlePlaceholder(mode: TmdbBuilderMode): String =
when (mode) {
TmdbBuilderMode.DISCOVER -> stringResource(Res.string.collections_editor_tmdb_discover_title_placeholder)
+ TmdbBuilderMode.PERSON -> stringResource(Res.string.collections_editor_tmdb_person_title_placeholder)
+ TmdbBuilderMode.DIRECTOR -> stringResource(Res.string.collections_editor_tmdb_director_title_placeholder)
else -> stringResource(Res.string.collections_editor_tmdb_title_placeholder)
}
@Composable
private fun tmdbSortLabel(sort: TmdbCollectionSort): String =
when (sort) {
+ TmdbCollectionSort.ORIGINAL -> stringResource(Res.string.collections_editor_tmdb_sort_original)
TmdbCollectionSort.POPULAR_DESC -> stringResource(Res.string.collections_editor_tmdb_sort_popular)
TmdbCollectionSort.VOTE_AVERAGE_DESC -> stringResource(Res.string.collections_editor_tmdb_sort_top_rated)
TmdbCollectionSort.RELEASE_DATE_DESC -> stringResource(Res.string.collections_editor_tmdb_sort_recent)
@@ -1979,6 +1998,16 @@ private fun tmdbSourceSubtitle(source: CollectionSource): String {
stringResource(Res.string.collections_editor_tmdb_series),
sort,
).joinToString(" • ")
+ TmdbCollectionSourceType.PERSON -> listOf(
+ stringResource(Res.string.collections_editor_tmdb_subtitle_person),
+ media,
+ sort,
+ ).joinToString(" • ")
+ TmdbCollectionSourceType.DIRECTOR -> listOf(
+ stringResource(Res.string.collections_editor_tmdb_subtitle_director),
+ media,
+ sort,
+ ).joinToString(" • ")
TmdbCollectionSourceType.DISCOVER -> listOf(
stringResource(Res.string.collections_editor_tmdb_subtitle_discover),
media,
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionModels.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionModels.kt
index 208aa03d..f0780ad2 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionModels.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/CollectionModels.kt
@@ -69,6 +69,8 @@ enum class TmdbCollectionSourceType {
COMPANY,
NETWORK,
DISCOVER,
+ PERSON,
+ DIRECTOR,
}
@Serializable
@@ -86,6 +88,7 @@ enum class TmdbCollectionMediaType(val value: String) {
}
enum class TmdbCollectionSort(val value: String) {
+ ORIGINAL("original"),
POPULAR_DESC("popularity.desc"),
VOTE_AVERAGE_DESC("vote_average.desc"),
RELEASE_DATE_DESC("primary_release_date.desc"),
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/FolderDetailRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/FolderDetailRepository.kt
index e853eeba..decff7a5 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/FolderDetailRepository.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/FolderDetailRepository.kt
@@ -140,7 +140,11 @@ object FolderDetailRepository {
source = source,
type = type,
catalogId = tmdbCatalogId(source),
- supportsPagination = source.tmdbSourceType != TmdbCollectionSourceType.COLLECTION.name,
+ supportsPagination = source.tmdbSourceType !in setOf(
+ TmdbCollectionSourceType.COLLECTION.name,
+ TmdbCollectionSourceType.PERSON.name,
+ TmdbCollectionSourceType.DIRECTOR.name,
+ ),
isLoading = true,
),
)
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/TmdbCollectionSourceResolver.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/TmdbCollectionSourceResolver.kt
index ee25fa48..3f37d3d8 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/TmdbCollectionSourceResolver.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/collection/TmdbCollectionSourceResolver.kt
@@ -29,6 +29,8 @@ object TmdbCollectionSourceResolver {
when (sourceType) {
TmdbCollectionSourceType.LIST -> resolveList(source, apiKey, language, page)
TmdbCollectionSourceType.COLLECTION -> resolveCollection(source, apiKey, language)
+ TmdbCollectionSourceType.PERSON,
+ TmdbCollectionSourceType.DIRECTOR -> resolvePersonCredits(source, apiKey, language)
TmdbCollectionSourceType.COMPANY,
TmdbCollectionSourceType.NETWORK,
TmdbCollectionSourceType.DISCOVER -> resolveDiscover(source, apiKey, language, page)
@@ -85,6 +87,19 @@ object TmdbCollectionSourceResolver {
)
}
+ TmdbCollectionSourceType.PERSON,
+ TmdbCollectionSourceType.DIRECTOR -> {
+ val body = fetch(
+ endpoint = "person/$id",
+ apiKey = apiKey,
+ query = mapOf("language" to language),
+ ) ?: error("TMDB person not found")
+ TmdbSourceImportMetadata(
+ title = body.name?.takeIf { it.isNotBlank() },
+ coverImageUrl = imageUrl(body.profilePath, "w500"),
+ )
+ }
+
TmdbCollectionSourceType.DISCOVER -> TmdbSourceImportMetadata(title = "TMDB Discover")
}
}
@@ -153,7 +168,7 @@ object TmdbCollectionSourceResolver {
fun parseTmdbId(input: String): Int? {
val trimmed = input.trim()
trimmed.toIntOrNull()?.let { return it }
- return Regex("""(?:list|collection|company|network)/(\d+)""")
+ return Regex("""(?:list|collection|company|network|person)/(\d+)""")
.find(trimmed)
?.groupValues
?.getOrNull(1)
@@ -193,6 +208,7 @@ object TmdbCollectionSourceResolver {
) ?: error("TMDB list not found")
val items = body.items.orEmpty()
.mapNotNull { it.toPreview() }
+ .sortedFor(source.sortBy)
.distinctBy { "${it.type}:${it.id}" }
return CatalogPage(
items = items,
@@ -213,12 +229,35 @@ object TmdbCollectionSourceResolver {
query = mapOf("language" to language),
) ?: error("TMDB collection not found")
val items = body.parts.orEmpty()
- .sortedBy { it.releaseDate ?: "9999" }
.mapNotNull { it.toPreview(TmdbCollectionMediaType.MOVIE) }
+ .sortedFor(source.sortBy)
.distinctBy { it.id }
return CatalogPage(items = items, rawItemCount = items.size, nextSkip = null)
}
+ private suspend fun resolvePersonCredits(
+ source: CollectionSource,
+ apiKey: String,
+ language: String,
+ ): CatalogPage {
+ val id = source.tmdbId ?: error("Missing TMDB person ID")
+ val mediaType = source.tmdbMediaType()
+ val body = fetch(
+ endpoint = "person/$id/combined_credits",
+ apiKey = apiKey,
+ query = mapOf("language" to language),
+ ) ?: error("TMDB person credits not found")
+ val items = when (source.tmdbType()) {
+ TmdbCollectionSourceType.DIRECTOR -> body.crew.orEmpty()
+ .filter { it.job.equals("Director", ignoreCase = true) }
+ .mapNotNull { it.toPreview(mediaType) }
+ else -> body.cast.orEmpty().mapNotNull { it.toPreview(mediaType) }
+ }
+ .distinctBy { "${it.type}:${it.id}" }
+ .sortedFor(source.sortBy)
+ return CatalogPage(items = items, rawItemCount = items.size, nextSkip = null)
+ }
+
private suspend fun resolveDiscover(
source: CollectionSource,
apiKey: String,
@@ -312,6 +351,21 @@ object TmdbCollectionSourceResolver {
}.getOrNull()
}
+ private fun List.sortedFor(sortBy: String?): List =
+ when (sortBy) {
+ TmdbCollectionSort.ORIGINAL.value -> this
+ TmdbCollectionSort.VOTE_AVERAGE_DESC.value -> sortedWith(
+ compareByDescending { it.imdbRating?.toDoubleOrNull() ?: -1.0 }
+ .thenByDescending { it.rawReleaseDate ?: it.releaseInfo.orEmpty() },
+ )
+ TmdbCollectionSort.RELEASE_DATE_DESC.value,
+ TmdbCollectionSort.FIRST_AIR_DATE_DESC.value -> sortedByDescending { it.rawReleaseDate ?: it.releaseInfo.orEmpty() }
+ TmdbCollectionSort.POPULAR_DESC.value,
+ null,
+ "" -> this
+ else -> this
+ }
+
private fun TmdbListItem.toPreview(): MetaPreview? {
val media = mediaType?.lowercase()
val contentType = if (media == "tv") TmdbCollectionMediaType.TV else TmdbCollectionMediaType.MOVIE
@@ -362,6 +416,62 @@ object TmdbCollectionSourceResolver {
)
}
+ private fun TmdbPersonCreditCast.toPreview(mediaType: TmdbCollectionMediaType): MetaPreview? {
+ if (!matchesMediaType(mediaType, this.mediaType)) return null
+ val title = title?.takeIf { it.isNotBlank() }
+ ?: name?.takeIf { it.isNotBlank() }
+ ?: originalTitle?.takeIf { it.isNotBlank() }
+ ?: originalName?.takeIf { it.isNotBlank() }
+ ?: return null
+ return MetaPreview(
+ id = "tmdb:$id",
+ type = if (mediaType == TmdbCollectionMediaType.TV) "series" else "movie",
+ name = title,
+ poster = imageUrl(posterPath, "w500") ?: imageUrl(backdropPath, "w780"),
+ banner = imageUrl(backdropPath, "w1280"),
+ posterShape = PosterShape.Poster,
+ description = overview?.takeIf { it.isNotBlank() },
+ releaseInfo = when (mediaType) {
+ TmdbCollectionMediaType.MOVIE -> releaseDate?.take(4)
+ TmdbCollectionMediaType.TV -> firstAirDate?.take(4)
+ },
+ rawReleaseDate = when (mediaType) {
+ TmdbCollectionMediaType.MOVIE -> releaseDate
+ TmdbCollectionMediaType.TV -> firstAirDate
+ },
+ popularity = popularity,
+ imdbRating = voteAverage?.let { ((it * 10).roundToInt() / 10.0).toString() },
+ )
+ }
+
+ private fun TmdbPersonCreditCrew.toPreview(mediaType: TmdbCollectionMediaType): MetaPreview? {
+ if (!matchesMediaType(mediaType, this.mediaType)) return null
+ val title = title?.takeIf { it.isNotBlank() }
+ ?: name?.takeIf { it.isNotBlank() }
+ ?: originalTitle?.takeIf { it.isNotBlank() }
+ ?: originalName?.takeIf { it.isNotBlank() }
+ ?: return null
+ return MetaPreview(
+ id = "tmdb:$id",
+ type = if (mediaType == TmdbCollectionMediaType.TV) "series" else "movie",
+ name = title,
+ poster = imageUrl(posterPath, "w500") ?: imageUrl(backdropPath, "w780"),
+ banner = imageUrl(backdropPath, "w1280"),
+ posterShape = PosterShape.Poster,
+ description = overview?.takeIf { it.isNotBlank() },
+ releaseInfo = when (mediaType) {
+ TmdbCollectionMediaType.MOVIE -> releaseDate?.take(4)
+ TmdbCollectionMediaType.TV -> firstAirDate?.take(4)
+ },
+ rawReleaseDate = when (mediaType) {
+ TmdbCollectionMediaType.MOVIE -> releaseDate
+ TmdbCollectionMediaType.TV -> firstAirDate
+ },
+ popularity = popularity,
+ imdbRating = voteAverage?.let { ((it * 10).roundToInt() / 10.0).toString() },
+ )
+ }
+
private fun CollectionSource.tmdbType(): TmdbCollectionSourceType =
tmdbSourceType
?.let { raw -> runCatching { TmdbCollectionSourceType.valueOf(raw.uppercase()) }.getOrNull() }
@@ -370,6 +480,12 @@ object TmdbCollectionSourceResolver {
private fun CollectionSource.tmdbMediaType(): TmdbCollectionMediaType =
TmdbCollectionMediaType.fromString(mediaType)
+ private fun matchesMediaType(expected: TmdbCollectionMediaType, actual: String?): Boolean =
+ when (expected) {
+ TmdbCollectionMediaType.MOVIE -> actual == "movie"
+ TmdbCollectionMediaType.TV -> actual == "tv"
+ }
+
private fun company(title: String, id: Int) = CollectionSource(
provider = "tmdb",
tmdbSourceType = TmdbCollectionSourceType.COMPANY.name,
@@ -391,6 +507,7 @@ object TmdbCollectionSourceResolver {
private fun movieSort(sortBy: String?): String =
when (sortBy) {
TmdbCollectionSort.FIRST_AIR_DATE_DESC.value -> TmdbCollectionSort.RELEASE_DATE_DESC.value
+ TmdbCollectionSort.ORIGINAL.value -> TmdbCollectionSort.POPULAR_DESC.value
null, "" -> TmdbCollectionSort.POPULAR_DESC.value
else -> sortBy
}
@@ -398,6 +515,7 @@ object TmdbCollectionSourceResolver {
private fun tvSort(sortBy: String?): String =
when (sortBy) {
TmdbCollectionSort.RELEASE_DATE_DESC.value -> TmdbCollectionSort.FIRST_AIR_DATE_DESC.value
+ TmdbCollectionSort.ORIGINAL.value -> TmdbCollectionSort.POPULAR_DESC.value
null, "" -> TmdbCollectionSort.POPULAR_DESC.value
else -> sortBy
}
@@ -449,6 +567,12 @@ private data class TmdbNetworkResponse(
@SerialName("logo_path") val logoPath: String? = null,
)
+@Serializable
+private data class TmdbPersonResponse(
+ val name: String? = null,
+ @SerialName("profile_path") val profilePath: String? = null,
+)
+
@Serializable
data class TmdbCompanySearchResult(
val id: Int,
@@ -496,6 +620,47 @@ private data class TmdbGenreItem(
val name: String,
)
+@Serializable
+private data class TmdbPersonCreditsResponse(
+ val cast: List? = null,
+ val crew: List? = null,
+)
+
+@Serializable
+private data class TmdbPersonCreditCast(
+ val id: Int,
+ @SerialName("media_type") val mediaType: String? = null,
+ val title: String? = null,
+ val name: String? = null,
+ @SerialName("original_title") val originalTitle: String? = null,
+ @SerialName("original_name") val originalName: String? = null,
+ val overview: String? = null,
+ @SerialName("poster_path") val posterPath: String? = null,
+ @SerialName("backdrop_path") val backdropPath: String? = null,
+ @SerialName("release_date") val releaseDate: String? = null,
+ @SerialName("first_air_date") val firstAirDate: String? = null,
+ @SerialName("vote_average") val voteAverage: Double? = null,
+ val popularity: Double? = null,
+)
+
+@Serializable
+private data class TmdbPersonCreditCrew(
+ val id: Int,
+ @SerialName("media_type") val mediaType: String? = null,
+ val title: String? = null,
+ val name: String? = null,
+ @SerialName("original_title") val originalTitle: String? = null,
+ @SerialName("original_name") val originalName: String? = null,
+ val overview: String? = null,
+ @SerialName("poster_path") val posterPath: String? = null,
+ @SerialName("backdrop_path") val backdropPath: String? = null,
+ @SerialName("release_date") val releaseDate: String? = null,
+ @SerialName("first_air_date") val firstAirDate: String? = null,
+ val job: String? = null,
+ @SerialName("vote_average") val voteAverage: Double? = null,
+ val popularity: Double? = null,
+)
+
@Serializable
private data class TmdbListItem(
val id: Int,