fix(trakt): preserve episode mapping identity

This commit is contained in:
tapframe 2026-07-22 21:19:12 +05:30
parent 58e57f2b17
commit cac2c891c0
4 changed files with 80 additions and 15 deletions

View file

@ -48,12 +48,19 @@ data class TrackingEpisode(
val title: String? = null,
)
data class TrackingCatalogReference(
val contentId: String,
val contentType: String,
val videoId: String? = null,
)
data class TrackingMediaReference(
val kind: TrackingMediaKind,
val title: String? = null,
val year: Int? = null,
val ids: TrackingExternalIds = TrackingExternalIds(),
val episode: TrackingEpisode? = null,
val catalog: TrackingCatalogReference? = null,
) {
val hasResolvableIdentity: Boolean
get() = ids.hasAny || !title.isNullOrBlank()
@ -146,6 +153,11 @@ fun buildTrackingMediaReference(
title = episodeTitle,
)
},
catalog = TrackingCatalogReference(
contentId = parentMetaId.trim(),
contentType = contentType.trim(),
videoId = videoId?.trim()?.takeIf(String::isNotBlank),
),
)
}

View file

@ -46,6 +46,33 @@ internal sealed interface TraktScrobbleItem {
}
}
internal data class TraktEpisodeMappingInput(
val contentId: String,
val contentType: String,
val videoId: String?,
val season: Int,
val episode: Int,
val episodeTitle: String?,
)
internal fun TrackingMediaReference.toTraktEpisodeMappingInput(): TraktEpisodeMappingInput? {
val episodeReference = episode ?: return null
val season = episodeReference.season ?: return null
val contentId = catalog?.contentId?.takeIf(String::isNotBlank)
?: ids.imdb?.takeIf(String::isNotBlank)
?: ids.tmdb?.let { value -> "tmdb:$value" }
?: ids.trakt?.let { value -> "trakt:$value" }
?: return null
return TraktEpisodeMappingInput(
contentId = contentId,
contentType = catalog?.contentType?.takeIf(String::isNotBlank) ?: "series",
videoId = catalog?.videoId?.takeIf(String::isNotBlank),
season = season,
episode = episodeReference.number,
episodeTitle = episodeReference.title,
)
}
internal object TraktScrobbleRepository : TrackingScrobbler {
override val providerId: TrackingProviderId = TrackingProviderId.TRAKT
@ -170,27 +197,22 @@ internal object TraktScrobbleRepository : TrackingScrobbler {
)
}
val episode = media.episode ?: return null
val season = episode.season ?: return null
val contentId = ids.imdb
?: ids.tmdb?.let { value -> "tmdb:$value" }
?: ids.trakt?.let { value -> "trakt:$value" }
?: return null
val mappingInput = media.toTraktEpisodeMappingInput() ?: return null
val mappedEpisode = TraktEpisodeMappingService.resolveEpisodeMapping(
contentId = contentId,
contentType = "series",
videoId = null,
season = season,
episode = episode.number,
episodeTitle = episode.title,
contentId = mappingInput.contentId,
contentType = mappingInput.contentType,
videoId = mappingInput.videoId,
season = mappingInput.season,
episode = mappingInput.episode,
episodeTitle = mappingInput.episodeTitle,
)
return TraktScrobbleItem.Episode(
showTitle = media.title,
showYear = media.year,
showIds = ids,
season = mappedEpisode?.season ?: season,
number = mappedEpisode?.episode ?: episode.number,
episodeTitle = episode.title,
season = mappedEpisode?.season ?: mappingInput.season,
number = mappedEpisode?.episode ?: mappingInput.episode,
episodeTitle = mappingInput.episodeTitle,
)
}

View file

@ -51,5 +51,8 @@ class TrackingMediaTest {
assertEquals(2016, media.year)
assertEquals(2, media.episode?.season)
assertEquals(7, media.episode?.number)
assertEquals("addon_specific_identifier", media.catalog?.contentId)
assertEquals("series", media.catalog?.contentType)
assertEquals("tt4574334:2:7", media.catalog?.videoId)
}
}

View file

@ -0,0 +1,28 @@
package com.nuvio.app.features.trakt
import com.nuvio.app.features.tracking.buildTrackingMediaReference
import kotlin.test.Test
import kotlin.test.assertEquals
class TraktScrobbleRepositoryTest {
@Test
fun episodeMappingInput_preservesAddonCatalogIdentity() {
val media = buildTrackingMediaReference(
contentType = "anime",
parentMetaId = "anime-addon:the-crow-girl",
videoId = "tt33307200:1:3",
title = "The Crow Girl",
seasonNumber = 1,
episodeNumber = 3,
episodeTitle = "Episode 3",
)
val input = media.toTraktEpisodeMappingInput()
assertEquals("anime-addon:the-crow-girl", input?.contentId)
assertEquals("anime", input?.contentType)
assertEquals("tt33307200:1:3", input?.videoId)
assertEquals(1, input?.season)
assertEquals(3, input?.episode)
}
}